writing-bicep-templates

star 102

Provides Bicep coding standards for Azure infrastructure in this repository. Use when writing or modifying Bicep files, configuring Container Apps, setting up RBAC, or working with Azure resources.

microsoft-foundry By microsoft-foundry schedule Updated 3/9/2026

name: writing-bicep-templates description: Provides Bicep coding standards for Azure infrastructure in this repository. Use when writing or modifying Bicep files, configuring Container Apps, setting up RBAC, or working with Azure resources.

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
Install via CLI
npx skills add https://github.com/microsoft-foundry/foundry-agent-webapp --skill writing-bicep-templates
Repository Details
star Stars 102
call_split Forks 154
navigation Branch main
article Path SKILL.md
More from Creator
microsoft-foundry
microsoft-foundry Explore all skills →