Skip to content

Commit a768d43

Browse files
feat(DTOSS-13037): automate enterprise app ownership via resource-group-init
Adds pipeline MI as owner of the enterprise app service principal and group members as owners of both the service principal and application registration using the Bicep Graph extension. Dynamically looks up the enterprise app client ID and group members in the deployment script, and sets uniqueName on the app registration to enable Bicep Graph extension lookup.
1 parent 4aad077 commit a768d43

5 files changed

Lines changed: 75 additions & 2 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"extensions": {
3+
"microsoftGraphV1": "br:mcr.microsoft.com/bicep/extensions/microsoftgraph/v1.0:1.0.0"
4+
}
5+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
extension microsoftGraphV1
2+
3+
param miPrincipalId string
4+
param enterpriseAppClientId string
5+
param enterpriseAppName string
6+
param groupMemberIds array = []
7+
8+
resource enterpriseAppSp 'Microsoft.Graph/servicePrincipals@v1.0' = {
9+
appId: enterpriseAppClientId
10+
owners: {
11+
relationships: concat([miPrincipalId], groupMemberIds)
12+
}
13+
}
14+
15+
resource enterpriseApp 'Microsoft.Graph/applications@v1.0' = {
16+
uniqueName: enterpriseAppName
17+
displayName: enterpriseAppName
18+
owners: {
19+
relationships: groupMemberIds
20+
}
21+
}

infrastructure/terraform/resource_group_init/main.bicep

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ param storageAccountRGName string
77
param storageAccountName string
88
param appShortName string
99
param userGroupPrincipalID string
10+
param enterpriseAppClientId string
11+
param groupMemberIds array = []
1012

1113
var hubMap = {
1214
dev: 'dev'
@@ -21,6 +23,7 @@ var privateDNSZoneRGName = 'rg-hub-${hubMap[envConfig]}-uks-private-dns-zones'
2123
var managedIdentityRGName = 'rg-mi-${envConfig}-uks'
2224
var infraResourceGroupName = 'rg-mbsgw-${envConfig}-infra'
2325
var keyVaultName = 'kv-mbsgw-${envConfig}-inf'
26+
var enterpriseAppName = 'spn-manbrs-web-api-${envConfig}'
2427

2528
var miADOtoAZname = 'mi-${appShortName}-${envConfig}-adotoaz-uks'
2629
var miGHtoADOname = 'mi-${appShortName}-${envConfig}-ghtoado-uks'
@@ -207,6 +210,17 @@ resource groupNetworkContributorAssignment 'Microsoft.Authorization/roleAssignme
207210
}
208211
}
209212

213+
module pipelineMiAppRole 'enterpriseAppOwner.bicep' = {
214+
name: 'pipelineMiAppRoleAssignment'
215+
scope: managedIdentityRG
216+
params: {
217+
miPrincipalId: managedIdentiyADOtoAZ.outputs.miPrincipalID
218+
enterpriseAppClientId: enterpriseAppClientId
219+
enterpriseAppName: enterpriseAppName
220+
groupMemberIds: groupMemberIds
221+
}
222+
}
223+
210224
output miPrincipalID string = managedIdentiyADOtoAZ.outputs.miPrincipalID
211225
output miName string = miADOtoAZname
212226
output keyVaultPrivateDNSZone string = keyVaultPrivateDNSZone.outputs.privateDNSZoneID

infrastructure/terraform/resource_group_init/managedIdentity.bicep

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ resource managedIdentiyGHtoADOFedCred 'Microsoft.ManagedIdentity/userAssignedIde
1414
}
1515

1616
output miPrincipalID string = mi.properties.principalId
17+
output miId string = mi.id

scripts/bash/resource_group_init.sh

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,43 @@ fi
2222

2323
echo "Found group Object ID: $userGroupPrincipalID"
2424

25+
echo "Fetching members of group: $userGroupName"
26+
groupMemberIds=$(az ad group member list --group "$userGroupName" --query "[].id" -o json)
27+
echo "Found group members: $groupMemberIds"
28+
29+
enterpriseAppName="spn-manbrs-web-api-${ENV_CONFIG}"
30+
echo "Fetching appId for enterprise app: $enterpriseAppName"
31+
enterpriseAppClientId=$(az ad sp list --filter "displayName eq '${enterpriseAppName}'" --query "[0].appId" -o tsv)
32+
33+
if [ -z "$enterpriseAppClientId" ]; then
34+
echo "Error: Enterprise app '$enterpriseAppName' not found in Entra ID"
35+
exit 1
36+
fi
37+
38+
echo "Found enterprise app client ID: $enterpriseAppClientId"
39+
40+
echo "Checking uniqueName on application registration $enterpriseAppName..."
41+
appObjectId=$(az ad app show --id "$enterpriseAppClientId" --query id -o tsv)
42+
currentUniqueName=$(az rest --method GET \
43+
--uri "https://graph.microsoft.com/v1.0/applications/${appObjectId}?\$select=uniqueName" \
44+
--query uniqueName -o tsv 2>/dev/null || echo "")
45+
if [ -z "$currentUniqueName" ]; then
46+
echo "Setting uniqueName to: $enterpriseAppName"
47+
az rest --method PATCH \
48+
--uri "https://graph.microsoft.com/v1.0/applications/${appObjectId}" \
49+
--headers "Content-Type=application/json" \
50+
--body "{\"uniqueName\": \"${enterpriseAppName}\"}"
51+
else
52+
echo "uniqueName already set to: $currentUniqueName"
53+
fi
54+
2555
echo "Deploy to hub subscription $HUB_SUBSCRIPTION_ID..."
2656
az deployment sub create --location "$REGION" --template-file infrastructure/terraform/resource_group_init/main.bicep \
2757
--subscription "$HUB_SUBSCRIPTION_ID" \
2858
--parameters enableSoftDelete="$ENABLE_SOFT_DELETE" envConfig="$ENV_CONFIG" region="$REGION" \
2959
storageAccountRGName="$STORAGE_ACCOUNT_RG" storageAccountName="$STORAGE_ACCOUNT_NAME" \
30-
appShortName="$APP_SHORT_NAME" userGroupPrincipalID="$userGroupPrincipalID" --what-if
60+
appShortName="$APP_SHORT_NAME" userGroupPrincipalID="$userGroupPrincipalID" \
61+
enterpriseAppClientId="$enterpriseAppClientId" groupMemberIds="$groupMemberIds" --what-if
3162

3263
read -r -p "Are you sure you want to execute the deployment? (y/n): " confirm
3364
[[ "$confirm" != "y" ]] && exit 0
@@ -36,7 +67,8 @@ output=$(az deployment sub create --location "$REGION" --template-file infrastru
3667
--subscription "$HUB_SUBSCRIPTION_ID" \
3768
--parameters enableSoftDelete="$ENABLE_SOFT_DELETE" envConfig="$ENV_CONFIG" region="$REGION" \
3869
storageAccountRGName="$STORAGE_ACCOUNT_RG" storageAccountName="$STORAGE_ACCOUNT_NAME" \
39-
appShortName="$APP_SHORT_NAME" userGroupPrincipalID="$userGroupPrincipalID")
70+
appShortName="$APP_SHORT_NAME" userGroupPrincipalID="$userGroupPrincipalID" \
71+
enterpriseAppClientId="$enterpriseAppClientId" groupMemberIds="$groupMemberIds")
4072

4173
echo "$output"
4274

0 commit comments

Comments
 (0)