Infrastructure as code with Bicep

Microsoft Azure · Practical · 15 min

IaC makes environments reproducible and reviewable; Bicep is Azure's native IaC language.

Bicep is a declarative language that compiles to ARM JSON templates. You describe the desired state; ARM works out what to create or update. There is no state file: Azure itself is the state.

Building blocks:

  • param: inputs, with types, defaults and decorators like @allowed, @minLength, @secure().
  • var: computed values.
  • resource sym 'Provider/type@apiVersion' = { ... }: a resource with a symbolic name you reference elsewhere (sa.id, sa.properties.primaryEndpoints). References create dependencies automatically.
  • output: values returned from the deployment.
  • module: another Bicep file deployed as a nested deployment, the unit of reuse. Azure Verified Modules publish well-tested ones in the public registry (br/public:avm/...).
  • existing: refer to a resource that is already deployed, without managing it.

Functions such as resourceGroup().location and uniqueString(resourceGroup().id) keep templates portable and names deterministic.

Deploy with az deployment group create (or sub, mg, tenant for other scopes) and keep parameters per environment in .bicepparam files. Run what-if before applying in production to preview creates, modifies and deletes. The Bicep VS Code extension gives completion and validation for every resource type and API version.

Example

// main.bicep
param location string = resourceGroup().location
@allowed(['dev', 'prod'])
param env string = 'dev'

var name = 'st${env}${uniqueString(resourceGroup().id)}'

resource sa 'Microsoft.Storage/storageAccounts@2023-05-01' = {
  name: name
  location: location
  sku: { name: env == 'prod' ? 'Standard_ZRS' : 'Standard_LRS' }
  kind: 'StorageV2'
  properties: {
    minimumTlsVersion: 'TLS1_2'
    allowBlobPublicAccess: false
  }
}

output blobEndpoint string = sa.properties.primaryEndpoints.blob
// az deployment group create -g rg-demo -f main.bicep -p env=prod

Remember

  • Bicep compiles to ARM JSON; Azure is the state
  • Symbolic references create dependencies automatically
  • Modules are the unit of reuse; check Azure Verified Modules first
  • Run what-if before production deployments

Watch out for

  • Hard-coding names and locations, so the template cannot deploy a second environment.

Check yourself

  1. How does Bicep know to create a storage account before a role assignment that uses sa.id?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview