main.tf (68 lines of code) (raw):
data "azapi_client_config" "current" {}
resource "azapi_resource" "identity" {
type = "Microsoft.ManagedIdentity/userAssignedIdentities@2023-07-31-preview"
parent_id = "/subscriptions/${data.azapi_client_config.current.subscription_id}/resourceGroups/${var.identity_resource_group_name}"
name = local.owner_repo_name
location = var.location
body = {} # empty body as HCL object is reqired to force output to be HCL and not JSON string.
response_export_values = [
"properties.principalId",
"properties.clientId",
"properties.tenantId"
]
}
resource "azapi_resource" "identity_federated_credentials" {
type = "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials@2023-07-31-preview"
name = local.owner_repo_name
parent_id = azapi_resource.identity.id
locks = [azapi_resource.identity.id] # not needed but added if we configure more than one environment
body = {
properties = {
audiences = ["api://AzureADTokenExchange"]
issuer = "https://token.actions.githubusercontent.com"
subject = "repo:${var.github_repository_owner}/${var.github_repository_name}:environment:${var.github_repository_environment_name}"
}
}
}
# Add owner role assignment.
# The condition prevents the assignee from creating new role assignments for owner, user access administratior, or role based access control administrator.
resource "azapi_resource" "identity_role_assignment" {
type = "Microsoft.Authorization/roleAssignments@2022-04-01"
name = uuidv5("url", "${var.github_repository_owner}${var.github_repository_name}${var.target_subscription_id}${data.azapi_client_config.current.tenant_id}")
parent_id = "/subscriptions/${var.target_subscription_id}"
body = {
properties = {
roleDefinitionId = "/subscriptions/${var.target_subscription_id}/providers/Microsoft.Authorization/roleDefinitions/${local.role_definition_name_owner}"
principalType = "ServicePrincipal"
principalId = azapi_resource.identity.output.properties.principalId
description = "Role assignment for AVM testing. Repo: ${var.github_repository_owner}/${var.github_repository_name}"
conditionVersion = "2.0"
condition = <<CONDITION
(
(
!(ActionMatches{'Microsoft.Authorization/roleAssignments/write'})
)
OR
(
@Request[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAllValues:GuidNotEquals {18d7d88d-d35e-4fb5-a5c3-7773c20a72d9, f58310d9-a9f6-439a-9e8d-f62e7b41a168}
)
)
AND
(
(
!(ActionMatches{'Microsoft.Authorization/roleAssignments/delete'})
)
OR
(
@Resource[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAllValues:GuidNotEquals {18d7d88d-d35e-4fb5-a5c3-7773c20a72d9, f58310d9-a9f6-439a-9e8d-f62e7b41a168}
)
)
CONDITION
}
}
}
data "azuread_group" "entra_readers" {
display_name = "grp-sec-avm-tf-end-to-end-testing-entra-readers"
}
resource "azuread_group_member" "example" {
group_object_id = data.azuread_group.entra_readers.object_id
member_object_id = azapi_resource.identity.output.properties.principalId
}