Phase 1 — Construction
La Phase 1 déploie une zone DNS primaire faisant autorité sur F5 Distributed Cloud avec Terraform, adossée à un état distant dans Azure Blob Storage. Cette page présente chaque fichier du plan, explique les variables et secrets requis, et couvre à la fois une exécution locale et le pipeline GitHub Actions.
Ce que vous déployez
Section intitulée « Ce que vous déployez »- Une
xcsh_dns_zonepour votre domaine délégué, dans le namespacesystem, avec un groupedemo-recordsd’enregistrements A (www,app,api). - L’état Terraform stocké dans un conteneur Azure Blob Storage, afin que le même état soit partagé entre votre machine et la CI.
Le plan réside sous terraform/ : un module racine léger qui relie les entrées à un module dns-zone.
versions.tf
Section intitulée « versions.tf »Fixe les versions de Terraform et du fournisseur. La contrainte du fournisseur est >= 3.62.0 — la version
où les ressources DNS exclusivement système définissent automatiquement leur namespace par défaut.
terraform { required_version = ">= 1.5"
required_providers { xcsh = { source = "f5-sales-demo/xcsh" # >= 3.62.0: the namespace attribute for system-only DNS resources defaults # to "system" (spec-driven), so it can be omitted. Locally the provider is # consumed via dev_overrides, which ignores this constraint. version = ">= 3.62.0" } }}providers.tf
Section intitulée « providers.tf »Le fournisseur ne prend aucun argument dans le code — il s’authentifie depuis l’environnement, donc aucun secret n’est validé dans le dépôt.
# The xcsh provider authenticates from the environment — no secrets in code.# Export one of the following credential sets before running Terraform:## Token auth: XCSH_API_URL + XCSH_API_TOKEN# P12 auth: XCSH_API_URL + XCSH_P12_FILE + XCSH_P12_PASSWORD# PEM auth: XCSH_API_URL + XCSH_CERT + XCSH_KEY## See terraform/README.md for local dev setup (dev_overrides + env).provider "xcsh" {}backend.tf
Section intitulée « backend.tf »Un backend azurerm partiel : aucune valeur spécifique à l’environnement n’est codée en dur. Les coordonnées
sont fournies au moment de init (depuis un fichier local, ou depuis les variables GitHub Actions en CI).
terraform { # Azure Blob Storage remote state, configured as a PARTIAL backend: # no environment-specific values are hardcoded here. Supply them at init time. # # CI: terraform init -backend-config="resource_group_name=$RG" ... # (values from GitHub Actions repository variables) # Local: terraform init -backend-config=backend.hcl (copy backend.hcl.example; gitignored) # # Auth is the storage account access key via the ARM_ACCESS_KEY environment # variable (never committed). Keyless auth (use_oidc / use_azuread_auth) is not # used: our Contributor-only RBAC cannot assign the "Storage Blob Data # Contributor" role those methods require. backend "azurerm" {}}variables.tf
Section intitulée « variables.tf »domain est requis (fourni à l’exécution, jamais codé en dur) ; a_records associe chaque nom d’enregistrement
à ses adresses IPv4. Il n’y a pas de variable namespace — le fournisseur fixe les objets DNS au namespace
system d’après la contrainte de la spécification API, donc il n’est jamais configuré ici.
variable "domain" { description = "DNS zone FQDN (required; supplied via TF_VAR_domain / a GitHub variable / tfvars)." type = string}
variable "labels" { description = "Labels applied to managed DNS objects." type = map(string) default = { managed_by = "terraform" use_case = "dns" }}
variable "a_records" { description = "A records: record name (\"\" = apex) to list of IPv4 addresses." type = map(list(string)) default = { www = ["203.0.113.10"] app = ["203.0.113.20"] api = ["203.0.113.30"] }}main.tf et le module dns-zone
Section intitulée « main.tf et le module dns-zone »Le module racine relie les entrées à ./modules/dns-zone :
module "dns_zone" { source = "./modules/dns-zone"
domain = var.domain labels = var.labels a_records = var.a_records}Le module crée la zone (le namespace est omis — le fournisseur le définit par défaut à system). Un bloc
dynamic "rr_set" transforme la map a_records en un jeu d’enregistrements par entrée :
resource "xcsh_dns_zone" "this" { name = var.domain labels = var.labels
primary { default_soa_parameters {}
rr_set_group { metadata { name = "demo-records" }
dynamic "rr_set" { for_each = var.a_records content { ttl = var.record_ttl a_record { name = rr_set.key values = rr_set.value } } } } }}Le fichier outputs.tf racine réexporte le nom de la zone et l’identifiant F5 XC depuis le module.
Variables et secrets requis
Section intitulée « Variables et secrets requis »Aucune valeur spécifique à l’environnement n’est intégrée dans les fichiers .tf. Tout est fourni à l’exécution
— depuis les variables et secrets GitHub Actions en CI, ou depuis des fichiers locaux et des variables
d’environnement.
| Valeur | Objectif | Source CI | Source locale |
|---|---|---|---|
resource_group_name, storage_account_name, container_name, key | Coordonnées du backend azurerm | Variables de dépôt TFSTATE_RESOURCE_GROUP, TFSTATE_STORAGE_ACCOUNT, TFSTATE_CONTAINER, TFSTATE_KEY (passées via -backend-config) | backend.hcl (copier backend.hcl.example ; gitignored) |
domain | Entrée Terraform | Variable de dépôt DNS_DOMAIN (sous forme de TF_VAR_domain) | terraform.tfvars (copier l’exemple) ou TF_VAR_domain |
ARM_ACCESS_KEY | Authentification du backend azurerm (clé du compte de stockage) | Secret de dépôt | export ARM_ACCESS_KEY=... |
XCSH_API_URL, XCSH_API_TOKEN | Authentification du fournisseur xcsh | Secrets de dépôt | export XCSH_API_URL=... XCSH_API_TOKEN=... |
Les deux fichiers d’exemple fournis dans le dépôt :
resource_group_name = "f5-sales-demo-tfstate"storage_account_name = "f5salesdemotfstate"container_name = "tfstate"key = "dns.tfstate"domain = "f5-sales-demo.com"
labels = { managed_by = "terraform" use_case = "dns"}
a_records = { www = ["203.0.113.10"] app = ["203.0.113.20"] api = ["203.0.113.30"]}Initialisation du backend d’état Azure
Section intitulée « Initialisation du backend d’état Azure »Le stockage du backend ne peut pas stocker son propre bootstrap, il faut donc le créer une seule fois, hors
bande, avec une session Azure CLI authentifiée. Le dépôt fournit scripts/bootstrap-azure-state.sh :
az group create --name f5-sales-demo-tfstate --location eastus2 \ --tags managed_by=terraform use_case=dns purpose=tfstate
az storage account create --name f5salesdemotfstate --resource-group f5-sales-demo-tfstate \ --location eastus2 --sku Standard_LRS --kind StorageV2 \ --min-tls-version TLS1_2 --allow-blob-public-access false
# State safety: keep prior versions and allow recovery of deleted state blobs.az storage account blob-service-properties update \ --account-name f5salesdemotfstate --resource-group f5-sales-demo-tfstate \ --enable-versioning true \ --enable-delete-retention true --delete-retention-days 7 \ --enable-container-delete-retention true --container-delete-retention-days 7
KEY="$(az storage account keys list \ --account-name f5salesdemotfstate --resource-group f5-sales-demo-tfstate \ --query '[0].value' -o tsv)"
az storage container create --name tfstate \ --account-name f5salesdemotfstate --auth-mode key --account-key "$KEY"Exportez ensuite la clé pour les exécutions locales, et définissez-la (ainsi que les identifiants du fournisseur) comme secrets GitHub :
export ARM_ACCESS_KEY="$KEY"gh secret set ARM_ACCESS_KEY -R f5-sales-demo/dnsgh secret set XCSH_API_URL -R f5-sales-demo/dnsgh secret set XCSH_API_TOKEN -R f5-sales-demo/dnsDéploiement en local
Section intitulée « Déploiement en local »-
Configurez les entrées. Copiez les exemples et renseignez vos valeurs :
Fenêtre de terminal cp terraform/backend.hcl.example terraform/backend.hclcp terraform/terraform.tfvars.example terraform/terraform.tfvars -
Exportez les identifiants :
Fenêtre de terminal export XCSH_API_URL="https://<tenant>.console.ves.volterra.io"export XCSH_API_TOKEN="<api-token>"export ARM_ACCESS_KEY="<storage-account-key>" -
Initialisez le backend avec la configuration partielle :
Fenêtre de terminal cd terraformterraform init -backend-config=backend.hcl -
Vérifiez le formatage et validez :
Fenêtre de terminal terraform fmt -check -recursiveterraform validate -
Planifiez et appliquez :
Fenêtre de terminal terraform planterraform apply
Une application réussie crée la zone et écrit l’état dans le conteneur Azure. Passez à la Phase 2 — Validation pour confirmer la résolution.
Intégration continue
Section intitulée « Intégration continue »Le workflow .github/workflows/terraform.yml exécute un plan à chaque pull request et un apply
lors d’une fusion dans main. Il lit les coordonnées du backend et les entrées depuis les variables de dépôt,
et les identifiants depuis les secrets, en les injectant uniquement dans l’étape qui en a besoin, et sérialise
les exécutions sur un groupe de concurrence afin que deux applications ne soient jamais en concurrence sur le
blob d’état partagé.
name: Terraform
on: pull_request: branches: [main] paths: ['terraform/**', '.github/workflows/terraform.yml'] push: branches: [main] paths: ['terraform/**']
permissions: contents: read
concurrency: group: terraform-state cancel-in-progress: false
env: TF_IN_AUTOMATION: 'true'
jobs: terraform: name: ${{ github.event_name == 'push' && 'apply' || 'plan' }} runs-on: ubuntu-latest defaults: run: working-directory: terraform steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Setup Terraform uses: hashicorp/setup-terraform@dfe3c3f87815947d99a8997f908cb6525fc44e9e # v4.0.1
- name: Init env: ARM_ACCESS_KEY: ${{ secrets.ARM_ACCESS_KEY }} RESOURCE_GROUP: ${{ vars.TFSTATE_RESOURCE_GROUP }} STORAGE_ACCOUNT: ${{ vars.TFSTATE_STORAGE_ACCOUNT }} CONTAINER: ${{ vars.TFSTATE_CONTAINER }} STATE_KEY: ${{ vars.TFSTATE_KEY }} run: | terraform init -input=false \ -backend-config="resource_group_name=${RESOURCE_GROUP}" \ -backend-config="storage_account_name=${STORAGE_ACCOUNT}" \ -backend-config="container_name=${CONTAINER}" \ -backend-config="key=${STATE_KEY}"
- name: Format check run: terraform fmt -check -recursive
- name: Validate run: terraform validate -no-color
- name: Plan if: github.event_name == 'pull_request' env: ARM_ACCESS_KEY: ${{ secrets.ARM_ACCESS_KEY }} XCSH_API_URL: ${{ secrets.XCSH_API_URL }} XCSH_API_TOKEN: ${{ secrets.XCSH_API_TOKEN }} TF_VAR_domain: ${{ vars.DNS_DOMAIN }} run: terraform plan -input=false -no-color
- name: Apply if: github.event_name == 'push' env: ARM_ACCESS_KEY: ${{ secrets.ARM_ACCESS_KEY }} XCSH_API_URL: ${{ secrets.XCSH_API_URL }} XCSH_API_TOKEN: ${{ secrets.XCSH_API_TOKEN }} TF_VAR_domain: ${{ vars.DNS_DOMAIN }} run: terraform apply -input=false -auto-approve -no-colorLes actions sont épinglées à des SHA de commit (avec des commentaires de version), et les secrets sont limités
aux étapes init, plan et apply plutôt qu’à l’ensemble du job.