Deployer()

Exploring the new Deployer() function in Bicep

Introduction

In the rapidly evolving landscape of cloud infrastructure, Infrastructure as Code (IaC) has become an indispensable practice for DevOps teams. Azure Bicep, Microsoft’s declarative language for deploying Azure resources, stands at the forefront of this movement, offering a concise and readable syntax for defining your cloud infrastructure. As deployments grow in complexity, spanning multiple subscriptions, management groups, or requiring dynamic permission assignments, managing the identity performing these deployments becomes a critical challenge.

This is where the new `Deployer()` function in Bicep emerges as a game-changer. It provides a powerful, built-in mechanism to dynamically retrieve information about the identity executing a Bicep deployment. Understanding and leveraging `Deployer()` is crucial for building robust, secure, and highly automated deployment pipelines. In this guide, you will learn the importance of this function, how to use it effectively for various scenarios, including cross-scope deployments, and how it simplifies identity management within your Azure IaC workflows.

Prerequisites

Before diving into the practical steps, ensure you have the following in place:

  • Azure Subscription: An active Azure subscription with permissions to create resource groups and assign roles (e.g., Contributor or Owner role at the subscription level for testing purposes).

  • Azure CLI: The latest version of Azure CLI installed and configured on your local machine.

  • Bicep CLI: The latest version of the Bicep CLI installed. You can install it via the Azure CLI: az bicep install.

  • Visual Studio Code: VS Code with the Bicep extension installed for an enhanced authoring experience.

  • Basic Bicep Knowledge: Familiarity with Bicep syntax, modules, and deploying resources.

  • Azure RBAC Understanding: A foundational understanding of Azure Role-Based Access Control (RBAC) concepts, including roles, role definitions, and principal IDs.

Step-by-Step Guide

1. Unveiling the Deployer() Function

The deployer() function in Bicep returns details about the identity that is executing the deployment. At present this includes the object ID, userPrincipalName and tenant ID as values.

Create a new Bicep file named main.bicep:

// Outputs
output deployer object = deployer()              

Now, deploy this Bicep file using the Azure CLI. You can deploy it at the resource group scope or subscription scope. For simplicity, let’s use the resource group scope.

# Deploy the Bicep file at the resource group scope
az deployment group create \
  --location eastus \
  --template-file main.bicep \
  --name GetDeployerInfoDemo

The output of the above command would be:

{
"objectId": "dqfewqfqewf-113b-4255-fdfewe-fdqwefew",
"tenantId": "fdfeqfewfq-3b1f-grr-fgr-fewfwqfwefwe",
"userPrincipalName": "UDevops@Devops.com"
}

2. Empowering the Deployer: Granting Necessary Permissions

One of the most common and powerful use cases for Deployer() is to dynamically assign permissions to the identity performing the deployment. This is particularly useful in scenarios where the deployer needs specific permissions on newly created resources or scopes that didn’t exist prior to the deployment.

Consider a scenario where your Bicep template creates a new resource group, and you want the identity that deployed it to automatically have Contributor access to that new resource group. This simplifies subsequent operations or auditing.

First, let’s create a reusable Bicep module for role assignments. Create a new folder named modules and inside it, a file named roleAssignment.bicep:

// modules/roleAssignment.bicep
// This module assigns a specified role to a principal at a given scope.

@description('The principal ID to which the role will be assigned.')
param principalId string

@description('The type of the principal (e.g., User, ServicePrincipal, ManagedIdentity, Group).')
param principalType string

@description('The full resource ID of the role definition (e.g., /providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c for Contributor).')
param roleDefinitionId string

@description('The scope at which the role assignment will be created. Defaults to the current resource group.')
param scope string = resourceGroup().id

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(principalId, roleDefinitionId, scope) // Generate a unique name for the role assignment
  scope: scope
  properties: {
    principalId: principalId
    roleDefinitionId: roleDefinitionId
    principalType: principalType
  }
}

Now, modify your main.bicep to create a new resource group and then assign the Contributor role to the deployer within that new resource group.

// main.bicep
// This Bicep file creates a new resource group and assigns the deployer
// Contributor role to it using the deployer() function.

@description('The location for the new resource group.')
param location string = resourceGroup().location

@description('A unique suffix for the resource group name to ensure uniqueness.')
param uniqueSuffix string = uniqueString(resourceGroup().id)

var newResourceGroupName = 'deployer-demo-rg-${uniqueSuffix}'
var contributorRoleDefinitionId = '/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' // Contributor role ID

// 1. Create a new resource group
resource newResourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
  name: newResourceGroupName
  location: location
}

// 2. Assign the Contributor role to the deployer on the newly created resource group
module assignDeployerContributor 'modules/roleAssignment.bicep' = {
  name: 'assign-deployer-contributor-${uniqueSuffix}'
  scope: newResourceGroup // The scope for this role assignment is the newly created resource group
  params: {
    principalId: deployer().principalId
    principalType: 'User'
    roleDefinitionId: contributorRoleDefinitionId
    scope: newResourceGroup.id // Explicitly pass the scope ID
  }
}

@description('The name of the newly created resource group.')
output createdResourceGroupName string = newResourceGroup.name

3. Resource Tagging in Azure with Bicep

Adding metadata to Azure resources is a key part of effective governance. By tagging resources with relevant contextual information—such as who deployed them and when—it becomes easier to audit, troubleshoot, and manage cost allocation.

Although not entirely foolproof, the approach below leverages Bicep’s capabilities to tag resources with critical deployment details.

Example of a tags parameter is defined with several required key-value pairs, including dynamic values populated during deployment:

@description('Optional set of resource tags.')
param tags object = {
  environment: envPrefix
  applicationName: 'Insight Path for AI'
  owner: 'Platform Team'
  criticality: 'Tier3'
  costCenter: '1234'
  contactEmail: 'test@outlook.com'
  dataClassification: 'Internal'
  provisioningTool: 'Bicep'
  deployedBy: deployer().objectId
  deploymentTimestamp: utcNow()
}

This allows you to quickly see who deployed a specific resource by inspecting its tags in the Azure Portal or via Azure CLI/PowerShell.

Conclusion

The Deployer() function in Bicep is a powerful addition that significantly enhances the flexibility, security, and automation capabilities of your Infrastructure as Code. By providing dynamic access to the identity performing a deployment, it simplifies complex scenarios like cross-subscription resource provisioning and enables intelligent, identity-aware infrastructure definitions.

By mastering the Deployer() function, you’re well on your way to building more robust, secure, and intelligent Azure infrastructure with Bicep.

You are currently viewing Exploring the new Deployer() function in Bicep