À la fin de ce tutoriel, vous saurez structurer une infra Bicep en modules, poser un
main.bicepcomposeur, lint/build en local, exécuter unwhat-ifpuis un déploiement idempotent via Azure Pipelines + OIDC, en régioncanadacentral, 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 DEHca-central-1cô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
- Bicep : premier template — vous avez déjà déployé un Storage lab en CLI
- Déployer Bicep avec Azure Pipelines — what-if / create basiques
- Service connections OIDC —
sc-ado-lab-oidcavec Contributor sur le RG cible - Démarrer avec Azure DevOps
- Azure CLI + Bicep (
az bicep version), repo Git, agent Microsoft-hostedubuntu-latest - Budget conscient : Storage LRS uniquement ; pas de VM, pas d’App Service Plan payant
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
- Bicep : premier template
- Déployer Bicep avec Azure Pipelines
- Service connections OIDC
- Azure ARM Templates
- Azure Workload Identity AKS (WOW 47)
- Policy-as-Code OPA
- Démarrer avec Azure DevOps
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)
Pour aller plus loin — hubs live
Retour parcours Catalogue Tutoriels — hub de la série et leçons sœurs.