À la fin de ce tutoriel, vous saurez structurer une infra Bicep en modules, poser un main.bicep composeur, lint/build en local, exécuter un what-if puis un déploiement idempotent via Azure Pipelines + OIDC, en région canadacentral, sans secrets dans Git.

Niveau : Intermédiaire → avancé · Temps estimé : 60–80 min · Versions cibles : Bicep CLI 2026 · Azure CLI · Azure Pipelines YAML · OIDC / WIF · Dernière vérification : 2026-09-11 · Region Azure : canadacentral (équivalent lab DEH ca-central-1 côté AWS)

Slug : wow-azure-bicep-advanced · Série : WOW (46/50) · Mot-clé SEO : Azure Bicep modules · Publish : HOLD

← Précédent : AWS Organizations multi-account · → Suivant : Azure Workload Identity AKS · Aussi : Bicep premier template · Bicep pipeline

Prérequis

Coût estimé : quelques centimes (Storage) + minutes d’agent Free ADO. Supprimez le RG en fin de lab.

az account show --query "{name:name, id:id}" -o table
az bicep version
export LOCATION=canadacentral

Ce que nous allons construire

Lab Bicep avancé (canadacentral) — WOW 46/50
  ├── infra/
  │     ├── main.bicep                 (composeur)
  │     ├── main.parameters.dev.json    (sans secrets)
  │     ├── bicepconfig.json           (lint / analyzers)
  │     └── modules/
  │           └── storage.bicep        (module Storage LRS)
  ├── azure-pipelines-bicep-adv.yml    (lint → what-if → deploy)
  ├── ADO : sc-ado-lab-oidc + env-lab
  └── Azure : rg-deh-bicep-adv → stadehXXXXX

(Schéma — alt : « Modules Bicep + pipeline Azure Pipelines OIDC vers canadacentral ».)

Objectif plateforme : une équipe app consomme un module Storage versionné ; la CI refuse un template qui ne lint pas et montre le diff avant d’écrire.

Étape 1 — Pourquoi des modules (pas un monolithe)

Un seul main.bicep de 800 lignes fonctionne… jusqu’à ce que trois équipes le forkent. Les modules Bicep encapsulent une capacité (storage, networking, monitoring) avec un contrat clair : paramètres d’entrée, outputs, tags DEH.

Approche Quand Risque
Monolithe Lab solo #14 Drift, copier-coller
Modules locaux ./modules Équipe / monorepo Choix DEH ici
Registry Bicep / ACR Multi-équipes, versioning semver Overhead lab

Règle DEH : un module = une responsabilité, tags Owner / Service / Env / CostCenter imposés côté composeur, zéro secret dans .bicep ou JSON commités.

Étape 2 — Arborescence et RG lab

mkdir -p ~/labs/deh-bicep-adv/infra/modules
cd ~/labs/deh-bicep-adv
git init 2>/dev/null || true
az group create -n rg-deh-bicep-adv -l canadacentral

Vérifiez que l’identité liée à sc-ado-lab-oidc a Contributor (ou moindre custom) sur ce RG seulement, pas sur tout l’abonnement.

Étape 3 — Module storage.bicep

Fichier infra/modules/storage.bicep — Storage Account LRS, HTTPS only, TLS 1.2, BPA-friendly (pas de blob public) :

@description('Nom globalement unique du Storage Account (3-24, minuscules/chiffres).')
@minLength(3)
@maxLength(24)
param name string

@description('Région Azure.')
param location string = resourceGroup().location

@description('Tags DEH obligatoires.')
param tags object

resource stg 'Microsoft.Storage/storageAccounts@2023-05-01' = {
  name: name
  location: location
  tags: tags
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    allowBlobPublicAccess: false
    minimumTlsVersion: 'TLS1_2'
    supportsHttpsTrafficOnly: true
    accessTier: 'Hot'
  }
}

output storageId string = stg.id
output storageName string = stg.name
output primaryBlobEndpoint string = stg.properties.primaryEndpoints.blob

Pas d’output de clé. Les clés / connection strings passent par Key Vault + RBAC ou Managed Identity — jamais dans les outputs de cours.

Étape 4 — Composeur main.bicep + paramètres

infra/main.bicep :

targetScope = 'resourceGroup'

@description('Suffixe unique (ex. uniqueString(rg.id) tronqué).')
@minLength(4)
@maxLength(10)
param uniqueSuffix string

@description('Environnement logique.')
@allowed(['dev', 'lab', 'prod'])
param environment string = 'lab'

@description('Owner pour FinOps / ownership.')
param owner string = 'deh-lab'

var storageName = 'stadeh${uniqueSuffix}'
var commonTags = {
  Owner: owner
  Service: 'deh-bicep-adv'
  Env: environment
  CostCenter: 'training'
  ManagedBy: 'bicep'
}

module storageModule 'modules/storage.bicep' = {
  name: 'storage-lab'
  params: {
    name: storageName
    location: resourceGroup().location
    tags: commonTags
  }
}

output storageAccountName string = storageModule.outputs.storageName
output storageAccountId string = storageModule.outputs.storageId

infra/main.parameters.dev.json (sans secrets) :

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "uniqueSuffix": {
      "value": "lab001"
    },
    "environment": {
      "value": "lab"
    },
    "owner": {
      "value": "deh-lab"
    }
  }
}

Adaptez uniqueSuffix pour garantir l’unicité globale du Storage Account (ex. lab + 4–5 caractères aléatoires).

Étape 5 — bicepconfig.json, lint et what-if local

infra/bicepconfig.json :

{
  "analyzers": {
    "core": {
      "enabled": true,
      "rules": {
        "no-hardcoded-env-urls": { "level": "warning" },
        "no-unused-params": { "level": "error" },
        "secure-secrets-in-params": { "level": "error" }
      }
    }
  }
}
cd ~/labs/deh-bicep-adv/infra
az bicep lint -f main.bicep
az bicep build -f main.bicep
# Preview sans écrire :
az deployment group what-if 
  -g rg-deh-bicep-adv 
  -f main.bicep 
  -p main.parameters.dev.json

Corrigez tout error lint avant de pousser. Le build génère l’ARM pour debug pédagogique — ne committez pas le JSON généré si votre convention est source-of-truth Bicep only.

Étape 6 — Déploiement CLI (validation manuelle)

az deployment group create 
  -g rg-deh-bicep-adv 
  -f main.bicep 
  -p main.parameters.dev.json 
  -n deh-bicep-adv-lab
az deployment group show -g rg-deh-bicep-adv -n deh-bicep-adv-lab 
  --query properties.outputs -o json

Relancez la même commande : déploiement idempotent. Changez un tag dans commonTags et refaites un what-if pour voir le diff.

Étape 7 — CI Azure Pipelines (lint → what-if → deploy)

azure-pipelines-bicep-adv.yml à la racine :

# azure-pipelines-bicep-adv.yml — WOW 46 — PAS de secrets
trigger:
  branches:
    include: [main]
  paths:
    include: [infra/**]

pr:
  branches:
    include: [main]
  paths:
    include: [infra/**]

variables:
  azureServiceConnection: 'sc-ado-lab-oidc'
  resourceGroup: 'rg-deh-bicep-adv'
  location: 'canadacentral'

stages:
- stage: Validate
  displayName: Lint + what-if
  jobs:
  - job: validate
    pool:
      vmImage: ubuntu-latest
    steps:
    - checkout: self
    - task: AzureCLI@2
      displayName: Bicep lint + what-if
      inputs:
        azureSubscription: $(azureServiceConnection)
        scriptType: bash
        scriptLocation: inlineScript
        inlineScript: |
          set -euo pipefail
          az bicep install
          az bicep lint -f infra/main.bicep
          az group create -n $(resourceGroup) -l $(location) --only-show-errors
          az deployment group what-if 
            -g $(resourceGroup) 
            -f infra/main.bicep 
            -p infra/main.parameters.dev.json

- stage: Deploy
  displayName: Deploy lab
  dependsOn: Validate
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
  jobs:
  - deployment: deployBicep
    environment: env-lab
    pool:
      vmImage: ubuntu-latest
    strategy:
      runOnce:
        deploy:
          steps:
          - checkout: self
          - task: AzureCLI@2
            displayName: az deployment group create
            inputs:
              azureSubscription: $(azureServiceConnection)
              scriptType: bash
              scriptLocation: inlineScript
              inlineScript: |
                set -euo pipefail
                az deployment group create 
                  -g $(resourceGroup) 
                  -f infra/main.bicep 
                  -p infra/main.parameters.dev.json 
                  -n deh-bicep-adv-$(Build.BuildId)

Créez le pipeline dans ADO pointant ce YAML. Sur PR : Validate seul. Sur main : Deploy derrière l’environnement env-lab (approvals optionnels). Auth = OIDC, pas de client secret dans les variables.

Variante GitHub Actions (sketch)

Si vous êtes hors ADO : permissions: id-token: write, azure/login OIDC, mêmes commandes az bicep lint / what-if / create, region canadacentral. Même contrat : pas de AZURE_CLIENT_SECRET long dans le repo.

Étape 8 — Patterns avancés (hors lab payant)

Pattern Intérêt Note DEH
User-defined types Contrats params stricts Bicep récent
existing + Key Vault ref Secrets hors template Préférer RBAC MI
Modules registry (ACR) Version semver partagée Après 2–3 modules stables
Subscription / MG scope Landing zone Hors scope Storage lab
what-if + Policy Guardrails Couplez avec OPA/Conftest WOW

Ne multipliez pas les scopes dans ce lab. Maîtrisez RG + modules locaux + CI d’abord.

Cleanup

az group delete -n rg-deh-bicep-adv --yes --no-wait

Vérifiez dans le portail / CLI que le RG disparaît. Les pipelines ADO peuvent rester (coût nul).

Erreurs fréquentes

Erreur Impact Correction
Nom Storage déjà pris Deploy fail Suffixe plus unique
Secrets dans parameters.json Fuite Git Key Vault / OIDC / variables secrètes ADO
Lint ignoré en CI Drift qualité az bicep lint en error gate
Contributor sur subscription entière Blast radius Scope RG rg-deh-bicep-adv
Deploy sans what-if Surprises Stage Validate obligatoire
Région eastus par défaut Hors standard DEH Forcer canadacentral
Module path cassé en pipeline File not found Paths relatifs depuis infra/ + checkout

Quiz (5 questions)

1. Un module Bicep sert surtout à : – A. Remplacer Azure CLI
– B. Encapsuler une capacité réutilisable avec contrat params/outputs
– C. Stocker des secrets

2. Avant un create en CI, DEH recommande : – A. Un delete du RG
– B. az bicep lint + az deployment group what-if
– C. Un export ARM édité à la main

3. Auth pipeline préférée 2026 : – A. Client secret dans le YAML
– B. OIDC / WIF (sc-ado-lab-oidc)
– C. User root Azure

4. Région lab Azure DEH dans ce tuto : – A. westeurope
– B. canadacentral
– C. us-east-1

5. Où mettent-on les clés Storage ? – A. Dans les outputs Bicep commités
– B. Hors template (RBAC / Key Vault / MI) — jamais dans Git
– C. En commentaire du module

Réponses : 1‑B · 2‑B · 3‑B · 4‑B · 5‑B

FAQ

Modules locaux ou Bicep Registry ?

Locaux pour démarrer (ce lab). Registry / ACR quand plusieurs repos consomment la même version semver.

Bicep remplace-t-il Terraform ?

Sur Azure pur, Bicep est le DSL natif Microsoft. Terraform reste multi-cloud. DEH enseigne les deux ; choisissez selon stack et compétences.

Faut-il committer l’ARM généré ?

Non si Bicep est la source de vérité. Gardez az bicep build pour debug / revue.

What-if est-il parfait ?

Non — cas limites (ressources data-plane, certains moves). Il reste le meilleur filet avant apply.

Pourquoi canadacentral et pas ca-central-1 ?

ca-central-1 est le code AWS. Sur Azure, l’équivalent lab DEH est canadacentral.

Combien de modules au MVP ?

Un ou deux (ex. storage + logs). Trop de modules trop tôt = indirection sans gain.

Pour aller plus loin

Maillage série WOW

← Précédent AWS Organizations multi-account
→ Suivant Azure Workload Identity sur AKS
Aussi Bicep pipeline · Trivy CI · DevSecOps

Meta publication (SEO)

  • Title SEO : Azure Bicep avancé : modules et CI (guide FR)
  • Meta description : Azure Bicep avancé : modules réutilisables, bicepconfig/lint, what-if et Azure Pipelines OIDC. Lab Storage LRS en canadacentral, FAQ et quiz DEH.
  • Focus keyword : Azure Bicep modules
  • Secondary : Bicep CI, Azure Pipelines Bicep, what-if Bicep, modules Bicep
  • Image : assets/web/devopelastichayway/cover-wow-azure-bicep-advanced-1200x630.webp (à générer)
  • Catégorie : WOW / Azure · Niveau : Intermédiaire → avancé
  • URL cible : https://devopelastichayway.com/tutoriels/wow-azure-bicep-advanced/
  • Post live : N/A (nouveau) · slug wow-azure-bicep-advanced · Publish : HOLD (draft only — feu vert Maître requis)

← Catalogue Tutoriels

Pour aller plus loin — hubs live

Retour parcours Catalogue Tutoriels — hub de la série et leçons sœurs.