From c119e0d279b3fbefb3cc1c5941b4a572ad33002d Mon Sep 17 00:00:00 2001 From: Antony Natale Date: Tue, 30 Apr 2024 16:13:27 -0400 Subject: [PATCH] updates to frontend and bicep to deploy and use workload identities --- Makefile | 42 +++++++++++++++---- deploy/aro-hcp-frontend.yml | 12 ++++++ dev-infrastructure/Makefile | 4 +- dev-infrastructure/docs/development-setup.md | 2 +- .../templates/aks-development.bicep | 28 ++++++++++++- dev-infrastructure/templates/rp-cosmos.bicep | 20 ++++++++- 6 files changed, 95 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 9be01f0da..c48f3cd27 100644 --- a/Makefile +++ b/Makefile @@ -25,19 +25,47 @@ frontend-build-container: docker build --platform="linux/amd64" -f "frontend/Dockerfile" -t ${ARO_HCP_FRONTEND_IMAGE} . frontend-deploy: - oc process -f ./deploy/aro-hcp-frontend.yml -p ARO_HCP_FRONTEND_IMAGE=${ARO_HCP_FRONTEND_IMAGE} --local | oc apply -f - - + @test "${RESOURCE_GROUP}" != "" || (echo "RESOURCE_GROUP must be defined" && exit 1) + FRONTEND_MI_CLIENT_ID=$(shell az deployment group show \ + -g ${RESOURCE_GROUP} \ + -n "hcp-${USER}-dev-infra" \ + --query properties.outputs.frontend_mi_client_id.value);\ + oc process -f ./deploy/aro-hcp-frontend.yml --local \ + -p ARO_HCP_FRONTEND_IMAGE=${ARO_HCP_FRONTEND_IMAGE} \ + -p FRONTEND_MI_CLIENT_ID="$${FRONTEND_MI_CLIENT_ID}" | oc apply -f - + frontend-undeploy: - oc process -f ./deploy/aro-hcp-frontend.yml -p ARO_HCP_FRONTEND_IMAGE=${ARO_HCP_FRONTEND_IMAGE} --local | oc delete -f - + @test "${RESOURCE_GROUP}" != "" || (echo "RESOURCE_GROUP must be defined" && exit 1) + FRONTEND_MI_CLIENT_ID=$(shell az deployment group show \ + -g ${RESOURCE_GROUP} \ + -n "hcp-${USER}-dev-infra" \ + --query properties.outputs.frontend_mi_client_id.value);\ + oc process -f ./deploy/aro-hcp-frontend.yml --local \ + -p ARO_HCP_FRONTEND_IMAGE=${ARO_HCP_FRONTEND_IMAGE} \ + -p FRONTEND_MI_CLIENT_ID="$${FRONTEND_MI_CLIENT_ID}" | oc delete -f - frontend-deploy-private: @test "${RESOURCE_GROUP}" != "" && test "${CLUSTER_NAME}" != "" || (echo "RESOURCE_GROUP and CLUSTER_NAME must be defined" && exit 1) - oc process -f ./deploy/aro-hcp-frontend.yml -p ARO_HCP_FRONTEND_IMAGE=${ARO_HCP_FRONTEND_IMAGE} --local > /tmp/deploy.yml - az aks command invoke --resource-group ${RESOURCE_GROUP} --name ${CLUSTER_NAME} --command "kubectl create -f deploy.yml" --file /tmp/deploy.yml + TMP_DEPLOY=$(shell mktemp);\ + FRONTEND_MI_CLIENT_ID=$(shell az deployment group show \ + -g ${RESOURCE_GROUP} \ + -n "hcp-${USER}-dev-infra" \ + --query properties.outputs.frontend_mi_client_id.value);\ + oc process -f ./deploy/aro-hcp-frontend.yml --local \ + -p ARO_HCP_FRONTEND_IMAGE=${ARO_HCP_FRONTEND_IMAGE} \ + -p FRONTEND_MI_CLIENT_ID="$${FRONTEND_MI_CLIENT_ID}" > "$${TMP_DEPLOY}";\ + az aks command invoke --resource-group ${RESOURCE_GROUP} --name ${CLUSTER_NAME} --command "kubectl create -f $$(basename $${TMP_DEPLOY})" --file "$${TMP_DEPLOY}" frontend-undeploy-private: @test "${RESOURCE_GROUP}" != "" && test "${CLUSTER_NAME}" != "" || (echo "RESOURCE_GROUP and CLUSTER_NAME must be defined" && exit 1) - oc process -f ./deploy/aro-hcp-frontend.yml -p ARO_HCP_FRONTEND_IMAGE=${ARO_HCP_FRONTEND_IMAGE} --local > /tmp/deploy.yml - az aks command invoke --resource-group ${RESOURCE_GROUP} --name ${CLUSTER_NAME} --command "kubectl delete -f deploy.yml" --file /tmp/deploy.yml + TMP_DEPLOY=$(shell mktemp);\ + FRONTEND_MI_CLIENT_ID=$(shell az deployment group show \ + -g ${RESOURCE_GROUP} \ + -n "hcp-${USER}-dev-infra" \ + --query properties.outputs.frontend_mi_client_id.value);\ + oc process -f ./deploy/aro-hcp-frontend.yml --local \ + -p ARO_HCP_FRONTEND_IMAGE=${ARO_HCP_FRONTEND_IMAGE} \ + -p FRONTEND_MI_CLIENT_ID="$${FRONTEND_MI_CLIENT_ID}" > "$${TMP_DEPLOY}";\ + az aks command invoke --resource-group ${RESOURCE_GROUP} --name ${CLUSTER_NAME} --command "kubectl delete -f $$(basename $${TMP_DEPLOY})" --file "$${TMP_DEPLOY}" .PHONY: frontend-build frontend-build-container frontend-deploy frontend-undeploy test lint clean diff --git a/deploy/aro-hcp-frontend.yml b/deploy/aro-hcp-frontend.yml index ff694df54..52a34ef6f 100644 --- a/deploy/aro-hcp-frontend.yml +++ b/deploy/aro-hcp-frontend.yml @@ -12,12 +12,22 @@ parameters: value: "1" - name: ARO_HCP_FRONTEND_IMAGE required: true +- name: FRONTEND_MI_CLIENT_ID + required: true + description: "Client ID of Frontend Managed Identity" objects: - apiVersion: v1 kind: Namespace metadata: name: ${NAMESPACE} +- apiVersion: v1 + kind: ServiceAccount + metadata: + annotations: + azure.workload.identity/client-id: ${FRONTEND_MI_CLIENT_ID} + name: frontend + namespace: ${NAMESPACE} - apiVersion: apps/v1 kind: Deployment metadata: @@ -41,7 +51,9 @@ objects: metadata: labels: app: aro-hcp-frontend + azure.workload.identity/use: "true" spec: + serviceAccountName: frontend containers: - name: aro-hcp-frontend image: ${ARO_HCP_FRONTEND_IMAGE} diff --git a/dev-infrastructure/Makefile b/dev-infrastructure/Makefile index 8085f4342..9a0f1b504 100644 --- a/dev-infrastructure/Makefile +++ b/dev-infrastructure/Makefile @@ -6,7 +6,7 @@ HCPDEVSUBSCRIPTIONID=1d3378d3-5a3f-4712-85a1-2485495dfc4b AKSTEMPLATE=templates/aks-development.bicep CURRENTUSER=$(shell az ad signed-in-user show | jq -r '.id') -DEPLOYMENTNAME=hcp-$(USER) +DEPLOYMENTNAME=hcp-$(USER)-dev-infra LOCATION?=eastus RESOURCEGROUP=aro-hcp-${AKSCONFIG}-$(USER) @@ -39,7 +39,7 @@ rg: setsubscription dev.infrastructure: setsubscription rg az deployment group create \ - --name "$(DEPLOYMENTNAME)-dev-infra" \ + --name "$(DEPLOYMENTNAME)" \ --resource-group $(RESOURCEGROUP) \ --template-file $(AKSTEMPLATE) \ --confirm-with-what-if \ diff --git a/dev-infrastructure/docs/development-setup.md b/dev-infrastructure/docs/development-setup.md index 66c82dc3d..abd3b4e13 100644 --- a/dev-infrastructure/docs/development-setup.md +++ b/dev-infrastructure/docs/development-setup.md @@ -42,7 +42,7 @@ In order for a resource provider to interact with a customers tenant, we create ### Step 1 - Log into the dev account Follow the "Preparation" steps -### Step 2 - Create the Application and its dependancies +### Step 2 - Create the Application and its dependencies Make sure you have `jq` installed on the system running the script. It is used to modify the role definition json file. diff --git a/dev-infrastructure/templates/aks-development.bicep b/dev-infrastructure/templates/aks-development.bicep index 7c0f3127a..86ea25170 100644 --- a/dev-infrastructure/templates/aks-development.bicep +++ b/dev-infrastructure/templates/aks-development.bicep @@ -96,9 +96,21 @@ var networkContributorRoleId = subscriptionResourceId( '4d97b98b-1d4f-4787-a291-c67834d212e7' ) -resource aro_rp_mi 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { +resource frontend_mi 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { location: location - name: 'aro-rp-${location}' + name: 'frontend-${location}' +} + +resource frontend_mi_fedcred 'Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials@2023-01-31' = { + name: 'frontend-${location}-fedcred' + parent: frontend_mi + properties: { + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: aksCluster.properties.oidcIssuerProfile.issuerURL + subject: 'system:serviceaccount:aro-hcp:frontend' + } } resource aks_nsg 'Microsoft.Network/networkSecurityGroups@2023-09-01' = { @@ -264,6 +276,14 @@ resource aksCluster 'Microsoft.ContainerService/managedClusters@2024-01-01' = { autoUpgradeProfile: { upgradeChannel: 'node-image' } + oidcIssuerProfile: { + enabled: true + } + securityProfile: { + workloadIdentity: { + enabled: true + } + } } } @@ -303,5 +323,9 @@ module nestedPeeringTemplate './rp-cosmos.bicep' = aksNodeSubnetId: aksNodeSubnet.id vnetId: vnet.id disableLocalAuth: disableLocalAuth + userAssignedMI: frontend_mi.id + uamiPrincipalId: frontend_mi.properties.principalId } } + +output frontend_mi_client_id string = frontend_mi.properties.clientId diff --git a/dev-infrastructure/templates/rp-cosmos.bicep b/dev-infrastructure/templates/rp-cosmos.bicep index b8afee28c..931e77fad 100644 --- a/dev-infrastructure/templates/rp-cosmos.bicep +++ b/dev-infrastructure/templates/rp-cosmos.bicep @@ -3,6 +3,8 @@ param disableLocalAuth bool = true param location string param aksNodeSubnetId string param vnetId string +param userAssignedMI string +param uamiPrincipalId string var containerNames = [ 'Subscriptions' @@ -11,10 +13,16 @@ var containerNames = [ 'Billing' ] +param roleDefinitionId string = '00000000-0000-0000-0000-000000000002' +var roleAssignmentId = guid(roleDefinitionId, uamiPrincipalId, cosmosDbAccount.id) + resource cosmosDbAccount 'Microsoft.DocumentDB/databaseAccounts@2023-11-15' = { kind: 'GlobalDocumentDB' identity: { - type: 'None' + type: 'UserAssigned' + userAssignedIdentities: { + '${userAssignedMI}': {} + } } name: name location: location @@ -164,3 +172,13 @@ resource cosmosDbContainers 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/ } } ] + +resource sqlRoleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2021-04-15' = { + name: roleAssignmentId + parent: cosmosDbAccount + properties: { + roleDefinitionId: '/${subscription().id}/resourceGroups/${resourceGroup().name}/providers/Microsoft.DocumentDB/databaseAccounts/${cosmosDbAccount.name}/sqlRoleDefinitions/${roleDefinitionId}' + principalId: uamiPrincipalId + scope: cosmosDbAccount.id + } +}