writing-bicep-templates

SKILL.md

Bicep Coding Standards

Goal: Create consistent, secure Azure infrastructure

Naming Convention

Use resourceToken from uniqueString():

var token = toLower(uniqueString(subscription().id, environmentName, location))
name: '${abbrs.appContainerApps}web-${token}'  // ca-web-abc123

Exception: ACR requires alphanumeric only: cr${resourceToken}

Parameters

Always add @description() and use @allowed() for constrained values:

@description('Environment (dev, prod)')
param environmentName string

@description('Azure region')
@allowed(['eastus2', 'westus2'])
param location string = 'eastus2'

Outputs

Expose key identifiers for azd and other modules:

output containerAppName string = containerApp.name
output webEndpoint string = 'https://${containerApp.properties.configuration.ingress.fqdn}'
output identityPrincipalId string = containerApp.identity.principalId

Managed Identity

Use a user-assigned MI for ACR pull and OBO (avoids circular dependencies). Create it in the infrastructure module so its principalId is available before the Container App:

resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30' = {
  name: '${abbrs.managedIdentityUserAssignedIdentities}web-${resourceToken}'
  location: location
  properties: { isolationScope: 'Regional' }
}
output managedIdentityPrincipalId string = managedIdentity.properties.principalId

Attach to Container App with identity: { type: 'UserAssigned', userAssignedIdentities: { '${miId}': {} } }. Use MI for ACR pull via registries: [{ server: acr.loginServer, identity: miId }].

RBAC Assignments

Use guid() for names + specify principalType:

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(resource.id, principalId, roleId)
  properties: {
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleId)
    principalId: principalId
    principalType: 'ServicePrincipal'
  }
}

Container Apps

Key settings: System identity + scale-to-zero + HTTPS only:

resource containerApp 'Microsoft.App/containerApps@2023-05-01' = {
  identity: { type: 'UserAssigned', userAssignedIdentities: { '${userAssignedIdentityId}': {} } }
  properties: {
    configuration: {
      ingress: {
        external: true
        targetPort: 8080
        allowInsecure: false
      }
    }
    template: {
      scale: { minReplicas: 0, maxReplicas: 3 }
    }
  }
}

ACR Pull Pattern

Use user-assigned MI for ACR pull (no admin credentials or secrets):

registries: [{
  server: containerRegistry.properties.loginServer
  identity: userAssignedIdentityId  // MI with AcrPull role
}]

Validation

az bicep build --file main.bicep
az deployment group what-if --template-file main.bicep

Project-Specific: Module Hierarchy

main.bicep (subscription scope)
├─ Resource group
├─ main-infrastructure.bicep (ACR + Container Apps Env + Log Analytics + User-Assigned MI)
├─ entra-app.bicep (SPA app + conditional OBO backend app with FIC + admin consent)
├─ main-app.bicep (Container App with MI-based ACR pull)
└─ RBAC (Cognitive Services User role via postprovision CLI)

Project-Specific: Container App Configuration

resource containerApp 'Microsoft.App/containerApps@2024-03-01' = {
  identity: {
    type: 'UserAssigned'
    userAssignedIdentities: { '${userAssignedIdentityId}': {} }
  }
  properties: {
    managedEnvironmentId: containerAppsEnvironmentId
    configuration: {
      ingress: {
        external: true
        targetPort: 8080
        allowInsecure: false
      }
      registries: [{
        server: containerRegistry.properties.loginServer
        identity: userAssignedIdentityId  // MI-based pull, no secrets
      }]
    }
    template: {
      containers: [{
        name: 'web'
        image: containerImage
        env: containerEnv  // Base env + conditional OBO env
        resources: { cpu: json('0.5'), memory: '1Gi' }
      }]
      scale: { minReplicas: 0, maxReplicas: 3 }
    }
  }
}

output fqdn string = containerApp.properties.configuration.ingress.fqdn
output identityPrincipalId string = containerApp.identity.principalId

Related Skills

  • deploying-to-azure - Deployment commands and hook workflow
  • writing-csharp-code - Backend configuration for Container Apps
  • troubleshooting-authentication - RBAC and managed identity debugging
Weekly Installs
10
GitHub Stars
66
First Seen
Feb 22, 2026
Installed on
codex10
opencode9
gemini-cli9
github-copilot9
amp9
kimi-cli9