Skip to content

Instantly share code, notes, and snippets.

@matejskubic
Last active June 23, 2026 07:11
Show Gist options
  • Select an option

  • Save matejskubic/937061eb3e332a5694f564c3ddb92c85 to your computer and use it in GitHub Desktop.

Select an option

Save matejskubic/937061eb3e332a5694f564c3ddb92c85 to your computer and use it in GitHub Desktop.
Deploy DevOps Infrastructure Initialization

Infrastructure Initialization

Deploy to Azure

Intention

This folder initializes the minimum Azure foundation needed for DevOps-driven infrastructure deployments.

What It Does

The initialization flow creates a dedicated identity resource group, provisions a user-assigned managed identity, optionally attaches workload federation, creates the target managed resource group, and grants delegated permission for controlled role assignment automation in that target scope.

Design

The main template orchestrates the setup and delegates permission assignment logic to a focused module.

Security Model

Delegation is intentionally constrained so the automation identity cannot assign or remove highly privileged RBAC roles, and all operational permissions stay scoped to the target managed resource group.

{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"languageVersion": "2.0",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.44.1.10279",
"templateHash": "1554478455842150772"
}
},
"parameters": {
"managedIdentityResourceGroupName": {
"type": "string",
"metadata": {
"description": "Name of the resource group to create for the DevOps managed identity."
}
},
"managedIdentityName": {
"type": "string",
"defaultValue": "[format('{0}-devOpsIdentity', parameters('managedIdentityResourceGroupName'))]",
"metadata": {
"description": "Name of the user-assigned managed identity used by DevOps pipelines."
}
},
"targetResourceGroupName": {
"type": "string",
"metadata": {
"description": "Name of the target resource group to create and manage through DevOps automation."
}
},
"location": {
"type": "string",
"defaultValue": "westeurope",
"metadata": {
"description": "Azure region for the created resource groups."
}
},
"resourceGroupTags": {
"type": "object",
"defaultValue": {},
"metadata": {
"description": "Optional tags applied to both created resource groups."
}
},
"managedIdentityLockDelete": {
"type": "bool",
"defaultValue": true,
"metadata": {
"description": "Optional flag to lock the managed identity from deletion. Lock is created only when federated credential is configured."
}
},
"contributorsEligible": {
"type": "array",
"items": {
"type": "string"
},
"defaultValue": [],
"metadata": {
"description": "Optional list of users/groups that should be eligible for the Contributor role on the managed resource group."
}
},
"contributorEligibilityDuration": {
"type": "string",
"defaultValue": "P180D",
"metadata": {
"description": "ISO 8601 duration for Contributor eligibility. Must comply with the applicable PIM expiration policy."
}
},
"federatedCredentialName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Optional federated credential name. Leave empty to skip creation."
}
},
"federatedCredentialIssuer": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Optional federated credential token issuer URL, for example https://vstoken.dev.azure.com/<organization-guid>."
}
},
"federatedCredentialSubject": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Optional federated credential subject claim, for example sc://org/project/service-connection."
}
},
"federatedCredentialAudiences": {
"type": "array",
"items": {
"type": "string"
},
"defaultValue": [],
"metadata": {
"description": "Optional federated credential audiences. Defaults to api://AzureADTokenExchange when empty."
}
}
},
"variables": {
"shouldCreateFederatedCredential": "[and(and(not(empty(parameters('federatedCredentialName'))), not(empty(parameters('federatedCredentialIssuer')))), not(empty(parameters('federatedCredentialSubject'))))]",
"resolvedFederatedAudiences": "[if(greater(length(parameters('federatedCredentialAudiences')), 0), parameters('federatedCredentialAudiences'), createArray('api://AzureADTokenExchange'))]"
},
"resources": {
"managedIdentityResourceGroup": {
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2024-03-01",
"name": "[parameters('managedIdentityResourceGroupName')]",
"location": "[parameters('location')]",
"tags": "[parameters('resourceGroupTags')]"
},
"managedResourceGroup": {
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2024-03-01",
"name": "[parameters('targetResourceGroupName')]",
"location": "[parameters('location')]",
"tags": "[parameters('resourceGroupTags')]"
},
"managedIdentitySetup": {
"type": "Microsoft.Resources/deployments",
"apiVersion": "2025-04-01",
"name": "[format('{0}-managedIdentity', deployment().name)]",
"resourceGroup": "[parameters('managedIdentityResourceGroupName')]",
"properties": {
"expressionEvaluationOptions": {
"scope": "inner"
},
"mode": "Incremental",
"parameters": {
"managedIdentityName": {
"value": "[parameters('managedIdentityName')]"
},
"managedIdentityLockDelete": {
"value": "[parameters('managedIdentityLockDelete')]"
},
"federatedCredentialName": {
"value": "[parameters('federatedCredentialName')]"
},
"federatedCredentialIssuer": {
"value": "[parameters('federatedCredentialIssuer')]"
},
"federatedCredentialSubject": {
"value": "[parameters('federatedCredentialSubject')]"
},
"federatedCredentialAudiences": {
"value": "[variables('resolvedFederatedAudiences')]"
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"languageVersion": "2.0",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.44.1.10279",
"templateHash": "16674321173291036278"
}
},
"parameters": {
"managedIdentityName": {
"type": "string",
"metadata": {
"description": "Name of the user-assigned managed identity."
}
},
"managedIdentityLockDelete": {
"type": "bool",
"defaultValue": true,
"metadata": {
"description": "Optional flag to lock the managed identity from deletion. Lock created only with federated credential."
}
},
"federatedCredentialName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Optional federated credential name. Leave empty to skip creation."
}
},
"federatedCredentialIssuer": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Optional federated credential token issuer URL."
}
},
"federatedCredentialSubject": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Optional federated credential subject claim."
}
},
"federatedCredentialAudiences": {
"type": "array",
"items": {
"type": "string"
},
"defaultValue": [],
"metadata": {
"description": "Optional federated credential audiences. Defaults to api://AzureADTokenExchange."
}
}
},
"variables": {
"shouldCreateFederatedCredential": "[and(and(not(empty(parameters('federatedCredentialName'))), not(empty(parameters('federatedCredentialIssuer')))), not(empty(parameters('federatedCredentialSubject'))))]",
"resolvedAudiences": "[if(greater(length(parameters('federatedCredentialAudiences')), 0), parameters('federatedCredentialAudiences'), createArray('api://AzureADTokenExchange'))]"
},
"resources": {
"devOpsIdentity": {
"type": "Microsoft.ManagedIdentity/userAssignedIdentities",
"apiVersion": "2024-11-30",
"name": "[parameters('managedIdentityName')]",
"location": "[resourceGroup().location]"
},
"devOpsFederatedCredential": {
"condition": "[variables('shouldCreateFederatedCredential')]",
"type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials",
"apiVersion": "2024-11-30",
"name": "[format('{0}/{1}', parameters('managedIdentityName'), parameters('federatedCredentialName'))]",
"properties": {
"issuer": "[parameters('federatedCredentialIssuer')]",
"subject": "[parameters('federatedCredentialSubject')]",
"audiences": "[variables('resolvedAudiences')]"
},
"dependsOn": [
"devOpsIdentity"
]
},
"devOpsIdentityLock": {
"condition": "[and(parameters('managedIdentityLockDelete'), variables('shouldCreateFederatedCredential'))]",
"type": "Microsoft.Authorization/locks",
"apiVersion": "2020-05-01",
"scope": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]",
"name": "used by DevOps",
"properties": {
"level": "CanNotDelete",
"notes": "[format('Managed identity lock for federated credential: {0}', parameters('federatedCredentialName'))]"
},
"dependsOn": [
"devOpsIdentity"
]
}
},
"outputs": {
"resourceId": {
"type": "string",
"value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]"
},
"clientId": {
"type": "string",
"value": "[reference('devOpsIdentity').clientId]"
},
"principalId": {
"type": "string",
"value": "[reference('devOpsIdentity').principalId]"
},
"federatedCredentialName": {
"type": "string",
"value": "[if(variables('shouldCreateFederatedCredential'), parameters('federatedCredentialName'), '')]"
}
}
}
},
"dependsOn": [
"managedIdentityResourceGroup"
]
},
"delegatedPermissions": {
"type": "Microsoft.Resources/deployments",
"apiVersion": "2025-04-01",
"name": "[format('{0}-delegatedPermissions', deployment().name)]",
"resourceGroup": "[parameters('targetResourceGroupName')]",
"properties": {
"expressionEvaluationOptions": {
"scope": "inner"
},
"mode": "Incremental",
"parameters": {
"managedIdentityName": {
"value": "[parameters('managedIdentityName')]"
},
"managedIdentityPrincipalId": {
"value": "[reference('managedIdentitySetup').outputs.principalId.value]"
},
"contributorsEligible": {
"value": "[parameters('contributorsEligible')]"
},
"contributorEligibilityDuration": {
"value": "[parameters('contributorEligibilityDuration')]"
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"languageVersion": "2.0",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.44.1.10279",
"templateHash": "13542600471294129976"
}
},
"parameters": {
"managedIdentityName": {
"type": "string",
"metadata": {
"description": "Name of the managed identity. Used only for deterministic role-assignment naming."
}
},
"managedIdentityPrincipalId": {
"type": "string",
"metadata": {
"description": "Principal ID of the managed identity."
}
},
"contributorsEligible": {
"type": "array",
"items": {
"type": "string"
},
"defaultValue": [],
"metadata": {
"description": "Optional list of users/groups that should be eligible for the Contributor role on the managed resource group."
}
},
"contributorEligibilityDuration": {
"type": "string",
"defaultValue": "P180D",
"metadata": {
"description": "ISO 8601 duration for Contributor eligibility. Must comply with the applicable PIM expiration policy."
}
},
"expirationStartDate": {
"type": "string",
"defaultValue": ""
},
"expirationDate": {
"type": "string",
"defaultValue": "[dateTimeAdd(utcNow(), parameters('contributorEligibilityDuration'))]"
},
"useRoundedDates": {
"type": "bool",
"defaultValue": false
}
},
"variables": {
"scheduleInfo": "[if(empty(parameters('expirationStartDate')), createObject('expiration', createObject('type', 'AfterDuration', 'duration', parameters('contributorEligibilityDuration'))), createObject('startDateTime', if(parameters('useRoundedDates'), dateTimeAdd(format('{0}0000Z', substring(parameters('expirationStartDate'), 0, 11)), 'PT1H'), parameters('expirationStartDate')), 'expiration', createObject('type', 'AfterDateTime', 'endDateTime', if(parameters('useRoundedDates'), dateTimeAdd(format('{0}-01T00:59:59Z', substring(parameters('expirationDate'), 0, 7)), '-PT8H'), parameters('expirationDate')))))]",
"ownerRoleDefinitionId": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635",
"contributorRoleDefinitionId": "b24988ac-6180-42a0-ab88-20f7382dd24c",
"roleAssignmentCondition": "(\r\n (\r\n !(ActionMatches{'Microsoft.Authorization/roleAssignments/write'})\r\n )\r\n OR\r\n (\r\n @Request[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAllValues:GuidNotEquals {\r\n 8e3af657-a8ff-443c-a75c-2fe8c4bcb635,\r\n 18d7d88d-d35e-4fb5-a5c3-7773c20a72d9,\r\n f58310d9-a9f6-439a-9e8d-f62e7b41a168\r\n }\r\n )\r\n)\r\nAND\r\n(\r\n (\r\n !(ActionMatches{'Microsoft.Authorization/roleAssignments/delete'})\r\n )\r\n OR\r\n (\r\n @Resource[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAllValues:GuidNotEquals {\r\n 8e3af657-a8ff-443c-a75c-2fe8c4bcb635,\r\n 18d7d88d-d35e-4fb5-a5c3-7773c20a72d9,\r\n f58310d9-a9f6-439a-9e8d-f62e7b41a168\r\n }\r\n )\r\n)\r\n"
},
"resources": {
"managedIdentityRoleDelegationAssignment": {
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2022-04-01",
"name": "[guid(resourceGroup().id, variables('ownerRoleDefinitionId'), parameters('managedIdentityName'), 'role-assignment-delegation')]",
"properties": {
"roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('ownerRoleDefinitionId'))]",
"principalId": "[parameters('managedIdentityPrincipalId')]",
"principalType": "ServicePrincipal",
"condition": "[variables('roleAssignmentCondition')]",
"conditionVersion": "2.0"
}
},
"contributorAssignments": {
"copy": {
"name": "contributorAssignments",
"count": "[length(parameters('contributorsEligible'))]"
},
"type": "Microsoft.Authorization/roleEligibilityScheduleRequests",
"apiVersion": "2022-04-01-preview",
"name": "[guid(resourceGroup().id, variables('contributorRoleDefinitionId'), parameters('contributorsEligible')[copyIndex()], 'eligible', deployment().name)]",
"properties": {
"principalId": "[parameters('contributorsEligible')[copyIndex()]]",
"roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('contributorRoleDefinitionId'))]",
"requestType": "AdminAssign",
"justification": "Provisioned by IaC deployment",
"scheduleInfo": "[variables('scheduleInfo')]"
}
}
},
"outputs": {
"managedIdentityOwnerRoleAssignmentId": {
"type": "string",
"value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(resourceGroup().id, variables('ownerRoleDefinitionId'), parameters('managedIdentityName'), 'role-assignment-delegation'))]"
},
"scheduledContributorInfo": {
"type": "object",
"value": "[variables('scheduleInfo')]"
}
}
}
},
"dependsOn": [
"managedIdentitySetup",
"managedResourceGroup"
]
}
},
"outputs": {
"identityResourceId": {
"type": "string",
"value": "[reference('managedIdentitySetup').outputs.resourceId.value]"
},
"identityClientId": {
"type": "string",
"value": "[reference('managedIdentitySetup').outputs.clientId.value]"
},
"identityPrincipalId": {
"type": "string",
"value": "[reference('managedIdentitySetup').outputs.principalId.value]"
},
"federatedCredentialName": {
"type": "string",
"value": "[if(variables('shouldCreateFederatedCredential'), reference('managedIdentitySetup').outputs.federatedCredentialName.value, '')]"
},
"managedResourceGroupId": {
"type": "string",
"value": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('targetResourceGroupName'))]"
},
"scheduledContributorInfo": {
"type": "object",
"value": "[reference('delegatedPermissions').outputs.scheduledContributorInfo.value]"
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment