From a50d8dc0020cf8266d6908665d8598d34361db2b Mon Sep 17 00:00:00 2001
From: Gerd Oberlechner <goberlec@redhat.com>
Date: Thu, 28 Nov 2024 14:24:07 +0100
Subject: [PATCH] devops MI keyvault cert creation on-demand permissions (#906)

* grant the devops MSI on-demand permissions when creating certs in KV
* move key-vault-cert module to keyvault folder
---
 .../configurations/mock-identities.bicepparam |  5 ---
 .../mock-identities.tmpl.bicepparam           |  5 +++
 .../keyvault/identity-script-msi.bicep        | 38 -------------------
 .../{ => keyvault}/key-vault-cert.bicep       | 14 +++++--
 .../modules/maestro/maestro-access-cert.bicep |  2 +-
 .../templates/mock-identities.bicep           | 34 ++++-------------
 6 files changed, 24 insertions(+), 74 deletions(-)
 delete mode 100644 dev-infrastructure/configurations/mock-identities.bicepparam
 create mode 100644 dev-infrastructure/configurations/mock-identities.tmpl.bicepparam
 delete mode 100644 dev-infrastructure/modules/keyvault/identity-script-msi.bicep
 rename dev-infrastructure/modules/{ => keyvault}/key-vault-cert.bicep (77%)

diff --git a/dev-infrastructure/configurations/mock-identities.bicepparam b/dev-infrastructure/configurations/mock-identities.bicepparam
deleted file mode 100644
index c923a3e13..000000000
--- a/dev-infrastructure/configurations/mock-identities.bicepparam
+++ /dev/null
@@ -1,5 +0,0 @@
-using '../templates/mock-identities.bicep'
-
-param kvCertOfficerManagedIdentityName = 'aro-hcp-dev-fp-kv-script'
-
-param keyVaultName = 'aro-hcp-dev-svc-kv'
diff --git a/dev-infrastructure/configurations/mock-identities.tmpl.bicepparam b/dev-infrastructure/configurations/mock-identities.tmpl.bicepparam
new file mode 100644
index 000000000..8cf3e7b3c
--- /dev/null
+++ b/dev-infrastructure/configurations/mock-identities.tmpl.bicepparam
@@ -0,0 +1,5 @@
+using '../templates/mock-identities.bicep'
+
+param aroDevopsMsiId = '{{ .aroDevopsMsiId }}'
+
+param keyVaultName = '{{ .serviceKeyVault.name }}'
diff --git a/dev-infrastructure/modules/keyvault/identity-script-msi.bicep b/dev-infrastructure/modules/keyvault/identity-script-msi.bicep
deleted file mode 100644
index 9f4eb4a89..000000000
--- a/dev-infrastructure/modules/keyvault/identity-script-msi.bicep
+++ /dev/null
@@ -1,38 +0,0 @@
-@description('Azure Region Location')
-param location string = resourceGroup().location
-
-@description('The name of the key vault')
-param keyVaultName string
-
-@description('Azure Region Location')
-param kvCertOfficerManagedIdentityName string
-
-//
-// M A N A G E D   I D E N T I T Y   C R E A T I O N
-//
-
-resource kv 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
-  name: keyVaultName
-}
-
-resource kvCertOfficerManagedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
-  name: kvCertOfficerManagedIdentityName
-  location: location
-}
-
-var keyVaultCertificateOfficerRoleId = subscriptionResourceId(
-  'Microsoft.Authorization/roleDefinitions/',
-  'a4417e6f-fecd-4de8-b567-7b0420556985'
-)
-
-resource kvManagedIdentityRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
-  scope: kv
-  name: guid(kvCertOfficerManagedIdentity.id, keyVaultCertificateOfficerRoleId, kv.id)
-  properties: {
-    roleDefinitionId: keyVaultCertificateOfficerRoleId
-    principalId: kvCertOfficerManagedIdentity.properties.principalId
-    principalType: 'ServicePrincipal'
-  }
-}
-
-output kvCertOfficerManagedIdentityId string = kvCertOfficerManagedIdentity.id
diff --git a/dev-infrastructure/modules/key-vault-cert.bicep b/dev-infrastructure/modules/keyvault/key-vault-cert.bicep
similarity index 77%
rename from dev-infrastructure/modules/key-vault-cert.bicep
rename to dev-infrastructure/modules/keyvault/key-vault-cert.bicep
index b8dfa91eb..090684dd8 100644
--- a/dev-infrastructure/modules/key-vault-cert.bicep
+++ b/dev-infrastructure/modules/keyvault/key-vault-cert.bicep
@@ -2,9 +2,6 @@
 Creating certificates in Azure Key Vault is not supported by Bicep yet.
 This module leverages a deploymentscript to solve this for the time beeing.
 Proudly stolen from https://github.com/Azure/bicep/discussions/8457
-
-We might not need certificates for MQTT authentication altogether if
-Entra autentication can be leveraged: https://redhat-external.slack.com/archives/C03F6AA3HDH/p1713340078776669
 */
 
 param keyVaultName string
@@ -19,6 +16,15 @@ param force bool = false
 var boolstring = force == false ? '$false' : '$true'
 param validityInMonths int = 12
 
+module certificateOfficerAccess 'keyvault-secret-access.bicep' = {
+  name: 'kv-cert-officer-access-${keyVaultName}-${uniqueString(keyVaultManagedIdentityId)}'
+  params: {
+    keyVaultName: keyVaultName
+    roleName: 'Key Vault Certificates Officer'
+    managedIdentityPrincipalId: reference(keyVaultManagedIdentityId, '2023-01-31').principalId
+  }
+}
+
 resource newCertwithRotationKV 'Microsoft.Resources/deploymentScripts@2023-08-01' = {
   name: 'newCertwithRotationKV-${certName}'
   identity: {
@@ -32,7 +38,7 @@ resource newCertwithRotationKV 'Microsoft.Resources/deploymentScripts@2023-08-01
   properties: {
     azPowerShellVersion: '12.0.0'
     arguments: ' -VaultName ${keyVaultName} -ValidityInMonths ${validityInMonths} -IssuerName ${issuerName} -CertName ${certName} -SubjectName ${subjectName} -DnsNames ${join(dnsNames,'_')} -Force ${boolstring}'
-    scriptContent: loadTextContent('../scripts/key-vault-cert.ps1')
+    scriptContent: loadTextContent('../../scripts/key-vault-cert.ps1')
     forceUpdateTag: now
     cleanupPreference: 'Always'
     retentionInterval: 'P1D'
diff --git a/dev-infrastructure/modules/maestro/maestro-access-cert.bicep b/dev-infrastructure/modules/maestro/maestro-access-cert.bicep
index 8df4b260b..6b8cd66cb 100644
--- a/dev-infrastructure/modules/maestro/maestro-access-cert.bicep
+++ b/dev-infrastructure/modules/maestro/maestro-access-cert.bicep
@@ -37,7 +37,7 @@ param certificateAccessManagedIdentityPrincipalId string
 
 var clientAuthenticationName = '${clientName}.${certDomain}'
 
-module clientCertificate '../key-vault-cert.bicep' = {
+module clientCertificate '../keyvault/key-vault-cert.bicep' = {
   name: '${clientName}-client-cert'
   params: {
     keyVaultName: keyVaultName
diff --git a/dev-infrastructure/templates/mock-identities.bicep b/dev-infrastructure/templates/mock-identities.bicep
index 84642508c..695792fa1 100644
--- a/dev-infrastructure/templates/mock-identities.bicep
+++ b/dev-infrastructure/templates/mock-identities.bicep
@@ -1,8 +1,8 @@
 @description('Azure Region Location')
 param location string = resourceGroup().location
 
-@description('Name of the Key Vault Certificate Officer Managed Identity')
-param kvCertOfficerManagedIdentityName string
+@description('The resource ID of the managed identity that will be used for Key Vault operations')
+param aroDevopsMsiId string
 
 @description('The name of the key vault')
 param keyVaultName string
@@ -10,33 +10,21 @@ param keyVaultName string
 @description('Global resource group name')
 param globalResourceGroupName string = 'global'
 
-module scriptMsi '../modules/keyvault/identity-script-msi.bicep' = {
-  name: 'script-msi'
-  params: {
-    location: location
-    kvCertOfficerManagedIdentityName: kvCertOfficerManagedIdentityName
-    keyVaultName: keyVaultName
-  }
-}
-
 //
 // F I R S T   P A R T Y   I D E N T I T Y
 //
 
-module firstPartyIdentity '../modules/key-vault-cert.bicep' = {
+module firstPartyIdentity '../modules/keyvault/key-vault-cert.bicep' = {
   name: 'first-party-identity'
   params: {
     location: location
-    keyVaultManagedIdentityId: scriptMsi.outputs.kvCertOfficerManagedIdentityId
+    keyVaultManagedIdentityId: aroDevopsMsiId
     keyVaultName: keyVaultName
     certName: 'firstPartyCert'
     subjectName: 'CN=firstparty.hcp.osadev.cloud'
     issuerName: 'Self'
     dnsNames: ['firstparty.hcp.osadev.cloud']
   }
-  dependsOn: [
-    scriptMsi
-  ]
 }
 
 resource customRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' = {
@@ -66,11 +54,11 @@ resource customRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' = {
 // A R M   H E L P E R   I D E N T I T Y
 //
 
-module armHelperIdentity '../modules/key-vault-cert.bicep' = {
+module armHelperIdentity '../modules/keyvault/key-vault-cert.bicep' = {
   name: 'arm-helper-identity'
   params: {
     location: location
-    keyVaultManagedIdentityId: scriptMsi.outputs.kvCertOfficerManagedIdentityId
+    keyVaultManagedIdentityId: aroDevopsMsiId
     keyVaultName: keyVaultName
     certName: 'armHelperCert'
     subjectName: 'CN=armhelper.hcp.osadev.cloud'
@@ -78,20 +66,17 @@ module armHelperIdentity '../modules/key-vault-cert.bicep' = {
     issuerName: 'Self'
     validityInMonths: 1000
   }
-  dependsOn: [
-    scriptMsi
-  ]
 }
 
 //
 // M S I   R P   M O CK   I D E N T I T Y
 //
 
-module msiRPMockIdentity '../modules/key-vault-cert.bicep' = {
+module msiRPMockIdentity '../modules/keyvault/key-vault-cert.bicep' = {
   name: 'msi-mock-identity'
   params: {
     location: location
-    keyVaultManagedIdentityId: scriptMsi.outputs.kvCertOfficerManagedIdentityId
+    keyVaultManagedIdentityId: aroDevopsMsiId
     keyVaultName: keyVaultName
     certName: 'msiMockCert'
     subjectName: 'CN=msimock.hcp.osadev.cloud'
@@ -99,7 +84,4 @@ module msiRPMockIdentity '../modules/key-vault-cert.bicep' = {
     issuerName: 'Self'
     validityInMonths: 1000
   }
-  dependsOn: [
-    scriptMsi
-  ]
 }