From d6a27562c3c5a7a893579ef999a4322ea9267551 Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Wed, 22 May 2024 11:25:07 +0200 Subject: [PATCH 1/9] Use own app identity for deployment of storage accounts --- .azure/applications/api/main.bicep | 67 +++++++------------ .azure/applications/api/params.bicepparam | 2 - .azure/applications/migration/main.bicep | 2 +- .azure/infrastructure/main.bicep | 33 +++++---- .azure/infrastructure/params.bicepparam | 1 - .azure/modules/containerApp/main.bicep | 39 +++++------ .azure/modules/identity/create.bicep | 24 +++++++ .../main.bicep | 0 .../actions/update-infrastructure/action.yml | 11 ++- .github/workflows/deploy-to-environment.yml | 3 - README-infrastructure.md | 7 +- .../Controllers/HealthController.cs | 4 +- .../Azure/AzureResourceManagerOptions.cs | 3 - .../Azure/AzureResourceManagerService.cs | 11 +-- 14 files changed, 99 insertions(+), 108 deletions(-) create mode 100644 .azure/modules/identity/create.bicep rename .azure/modules/{containerAppJob => migrationJob}/main.bicep (100%) diff --git a/.azure/applications/api/main.bicep b/.azure/applications/api/main.bicep index c29f1060..99b421b9 100644 --- a/.azure/applications/api/main.bicep +++ b/.azure/applications/api/main.bicep @@ -1,4 +1,4 @@ -targetScope = 'resourceGroup' +targetScope = 'subscription' @minLength(3) param imageTag string @@ -15,90 +15,73 @@ param maskinporten_environment string param sourceKeyVaultName string @secure() param keyVaultUrl string - -@secure() -param client_id string - -@secure() -param tenant_id string @secure() param namePrefix string -var baseImageUrl = 'ghcr.io/altinn/altinn-broker' var containerAppName = '${namePrefix}-app' -resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { - name: '${namePrefix}-app-identity' +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'namePrefix-rg' location: location } + +module appIdentity '../../modules/identity/create.bicep' = { + name: 'appIdentity' + scope: resourceGroup + params: { + namePrefix: namePrefix + location: location + } +} + module keyVaultReaderAccessPolicyUserIdentity '../../modules/keyvault/addReaderRoles.bicep' = { name: 'kvreader-${namePrefix}-app' + scope: resourceGroup params: { keyvaultName: sourceKeyVaultName - tenantId: userAssignedIdentity.properties.tenantId - principalIds: [userAssignedIdentity.properties.principalId] + tenantId: appIdentity.outputs.tenantId + principalIds: [appIdentity.outputs.principalId] } } module databaseAccess '../../modules/postgreSql/AddAdministrationAccess.bicep' = { name: 'databaseAccess' + scope: resourceGroup dependsOn: [ keyVaultReaderAccessPolicyUserIdentity // Timing issue ] params: { - tenantId: userAssignedIdentity.properties.tenantId - principalId: userAssignedIdentity.properties.principalId - appName: userAssignedIdentity.name + tenantId: appIdentity.outputs.tenantId + principalId: appIdentity.outputs.principalId + appName: appIdentity.name namePrefix: namePrefix } } resource keyvault 'Microsoft.KeyVault/vaults@2023-07-01' existing = { name: sourceKeyVaultName + scope: resourceGroup } module containerApp '../../modules/containerApp/main.bicep' = { name: containerAppName + scope: resourceGroup dependsOn: [keyVaultReaderAccessPolicyUserIdentity, databaseAccess] params: { namePrefix: namePrefix - image: '${baseImageUrl}:${imageTag}' + image: imageTag location: location environment: environment - client_id: client_id - tenant_id: tenant_id subscription_id: subscription().subscriptionId - principal_id: userAssignedIdentity.id + principal_id: appIdentity.outputs.id platform_base_url: platform_base_url keyVaultUrl: keyVaultUrl maskinporten_environment: maskinporten_environment - malwarescan_event_grid_topic_name: eventgrid_topic.name - userIdentityTenantId: userAssignedIdentity.properties.tenantId - userIdentityClientId: userAssignedIdentity.properties.clientId - userIdentityPrincipalId: userAssignedIdentity.properties.principalId + userIdentityClientId: appIdentity.outputs.clientId containerAppEnvId: keyvault.getSecret('container-app-env-id') } } -resource eventgrid_topic 'Microsoft.EventGrid/topics@2022-06-15' = { - name: '${namePrefix}-malware-scan-event-topic' - location: location -} - -resource eventgrid_event_subscription 'Microsoft.EventGrid/topics/eventSubscriptions@2022-06-15' = { - name: '${namePrefix}-malware-scan-event-subscription' - parent: eventgrid_topic - dependsOn: [containerApp] - properties: { - destination: { - endpointType: 'WebHook' - properties: { - endpointUrl: 'https://${containerApp.outputs.app.properties.configuration.ingress.fqdn}/broker/api/v1/webhooks/malwarescanresults' - } - } - } -} - output name string = containerApp.outputs.name output revisionName string = containerApp.outputs.revisionName diff --git a/.azure/applications/api/params.bicepparam b/.azure/applications/api/params.bicepparam index 1489aad1..feda2cd9 100644 --- a/.azure/applications/api/params.bicepparam +++ b/.azure/applications/api/params.bicepparam @@ -9,5 +9,3 @@ param environment = readEnvironmentVariable('ENVIRONMENT') // secrets param sourceKeyVaultName = readEnvironmentVariable('KEY_VAULT_NAME') param keyVaultUrl = readEnvironmentVariable('KEY_VAULT_URL') -param client_id = readEnvironmentVariable('CLIENT_ID') -param tenant_id = readEnvironmentVariable('TENANT_ID') diff --git a/.azure/applications/migration/main.bicep b/.azure/applications/migration/main.bicep index 9f3d6b92..04d31752 100644 --- a/.azure/applications/migration/main.bicep +++ b/.azure/applications/migration/main.bicep @@ -74,7 +74,7 @@ resource containerAppEnv 'Microsoft.App/managedEnvironments@2023-11-02-preview' name: containerAppEnvName } -module containerAppJob '../../modules/containerAppJob/main.bicep' = { +module containerAppJob '../../modules/migrationJob/main.bicep' = { name: containerAppJobName dependsOn: [ addKeyvaultRead diff --git a/.azure/infrastructure/main.bicep b/.azure/infrastructure/main.bicep index a1bb7866..61f1ce69 100644 --- a/.azure/infrastructure/main.bicep +++ b/.azure/infrastructure/main.bicep @@ -11,8 +11,6 @@ param tenantId string param azureClientId string @secure() param test_client_id string -@secure() -param deploySecret string param environment string @secure() param namePrefix string @@ -37,18 +35,6 @@ param postgresSku PostgresSku var resourceGroupName = '${namePrefix}-rg' var secrets = [ - { - name: 'deploy-id' - value: azureClientId - } - { - name: 'deploy-secret' - value: deploySecret - } - { - name: 'deploy-tenant-id' - value: tenantId - } { name: 'maskinporten-client-id' value: maskinportenClientId @@ -69,6 +55,25 @@ resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { location: location } +resource StorageAccounts 'Microsoft.Security/pricings@2024-01-01' = { + name: 'StorageAccounts' + properties: { + pricingTier: 'Standard' + + subPlan: 'DefenderForStorageV2' + extensions: [ + { + name: 'OnUploadMalwareScanning' + isEnabled: 'True' + } + { + name: 'SensitiveDataDiscovery' + isEnabled: 'True' + } + ] + } +} + module environmentKeyVault '../modules/keyvault/create.bicep' = { scope: resourceGroup name: 'keyVault' diff --git a/.azure/infrastructure/params.bicepparam b/.azure/infrastructure/params.bicepparam index 2ba2ade3..cc65bc54 100644 --- a/.azure/infrastructure/params.bicepparam +++ b/.azure/infrastructure/params.bicepparam @@ -11,7 +11,6 @@ param azureClientId = readEnvironmentVariable('CLIENT_ID') param test_client_id = readEnvironmentVariable('TEST_CLIENT_ID') param sourceKeyVaultName = readEnvironmentVariable('KEY_VAULT_NAME') param migrationsStorageAccountName = readEnvironmentVariable('MIGRATION_STORAGE_ACCOUNT_NAME') -param deploySecret = readEnvironmentVariable('CLIENT_SECRET') param maskinportenJwk = readEnvironmentVariable('MASKINPORTEN_JWK') param maskinportenClientId = readEnvironmentVariable('MASKINPORTEN_CLIENT_ID') param platformSubscriptionKey = readEnvironmentVariable('PLATFORM_SUBSCRIPTION_KEY') diff --git a/.azure/modules/containerApp/main.bicep b/.azure/modules/containerApp/main.bicep index 676e6ccc..cd8ae582 100644 --- a/.azure/modules/containerApp/main.bicep +++ b/.azure/modules/containerApp/main.bicep @@ -9,22 +9,12 @@ param maskinporten_environment string @secure() param subscription_id string @secure() -param client_id string -@secure() -param tenant_id string -@secure() param principal_id string @secure() param keyVaultUrl string @secure() -param malwarescan_event_grid_topic_name string -@secure() -param userIdentityTenantId string -@secure() param userIdentityClientId string @secure() -param userIdentityPrincipalId string -@secure() param containerAppEnvId string var probes = [ @@ -44,11 +34,8 @@ var containerAppEnvVars = [ { name: 'AzureResourceManagerOptions__SubscriptionId', value: subscription_id } { name: 'AzureResourceManagerOptions__Location', value: 'norwayeast' } { name: 'AzureResourceManagerOptions__Environment', value: environment } - { name: 'AzureResourceManagerOptions__ClientId', value: client_id } - { name: 'AzureResourceManagerOptions__TenantId', value: tenant_id } - { name: 'AzureResourceManagerOptions__ClientSecret', secretRef: 'deploy-client-secret' } { name: 'AzureResourceManagerOptions__ApplicationResourceGroupName', value: '${namePrefix}-rg' } - { name: 'AzureResourceManagerOptions__MalwareScanEventGridTopicName', value: malwarescan_event_grid_topic_name } + { name: 'AzureResourceManagerOptions__MalwareScanEventGridTopicName', value: eventgrid_topic.name } { name: 'AZURE_CLIENT_ID', value: userIdentityClientId } { name: 'AltinnOptions__OpenIdWellKnown' @@ -81,11 +68,6 @@ resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { transport: 'Auto' } secrets: [ - { - identity: principal_id - keyVaultUrl: '${keyVaultUrl}/secrets/deploy-secret' - name: 'deploy-client-secret' - } { identity: principal_id keyVaultUrl: '${keyVaultUrl}/secrets/platform-subscription-key' @@ -168,6 +150,25 @@ resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { } } +resource eventgrid_topic 'Microsoft.EventGrid/topics@2022-06-15' = { + name: '${namePrefix}-malware-scan-event-topic' + location: location +} + +resource eventgrid_event_subscription 'Microsoft.EventGrid/topics/eventSubscriptions@2022-06-15' = { + name: '${namePrefix}-malware-scan-event-subscription' + parent: eventgrid_topic + properties: { + destination: { + endpointType: 'WebHook' + properties: { + endpointUrl: 'https://${containerApp.properties.configuration.ingress.fqdn}/broker/api/v1/webhooks/malwarescanresults' + } + } + } +} + output name string = containerApp.name output revisionName string = containerApp.properties.latestRevisionName output app object = containerApp +output eventGridTopicName string = eventgrid_topic.name diff --git a/.azure/modules/identity/create.bicep b/.azure/modules/identity/create.bicep new file mode 100644 index 00000000..d70e17e1 --- /dev/null +++ b/.azure/modules/identity/create.bicep @@ -0,0 +1,24 @@ +@secure() +param namePrefix string +param location string + + +resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: '${namePrefix}-app-identity' + location: location +} + +var roleDefinitionResourceId = 'b24988ac-6180-42a0-ab88-20f7382dd24c' // Contributor role +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscription().id, userAssignedIdentity.id, roleDefinitionResourceId) + properties: { + roleDefinitionId: roleDefinitionResourceId + principalId: userAssignedIdentity.id + principalType: 'ServicePrincipal' + } +} + +output id string = userAssignedIdentity.id +output clientId string = userAssignedIdentity.properties.clientId +output principalId string = userAssignedIdentity.properties.principalId +output tenantId string = userAssignedIdentity.properties.tenantId diff --git a/.azure/modules/containerAppJob/main.bicep b/.azure/modules/migrationJob/main.bicep similarity index 100% rename from .azure/modules/containerAppJob/main.bicep rename to .azure/modules/migrationJob/main.bicep diff --git a/.github/actions/update-infrastructure/action.yml b/.github/actions/update-infrastructure/action.yml index 132012f2..f8691fad 100644 --- a/.github/actions/update-infrastructure/action.yml +++ b/.github/actions/update-infrastructure/action.yml @@ -24,15 +24,13 @@ inputs: AZURE_TENANT_ID: description: "Tenant ID for the service principal" required: true + required: true AZURE_TEST_ACCESS_CLIENT_ID: description: "Client ID for the test access service principal" required: true AZURE_MIGRATION_STORAGE_ACCOUNT_NAME: description: "Name of the storage account for migration files" required: true - AZURE_CLIENT_SECRET: - description: "Client secret for the service principal" - required: true MASKINPORTEN_JWK: description: "JWK for maskinporten" required: true @@ -77,15 +75,16 @@ runs: uses: azure/arm-deploy@v2 id: deploy env: - NAME_PREFIX: ${{ inputs.AZURE_NAME_PREFIX }} ENVIRONMENT: ${{ inputs.environment }} BROKER_PG_ADMIN_PASSWORD: ${{ steps.pwd-generator.outputs.postgresqlPassword }} - TENANT_ID: ${{ inputs.AZURE_TENANT_ID }} + AZURE_NAME_PREFIX: ${{ inputs.AZURE_NAME_PREFIX }} + SOURCE_KEY_VAULT_NAME: ${{ inputs.AZURE_ENVIRONMENT_KEY_VAULT_NAME }} CLIENT_ID: ${{ inputs.AZURE_CLIENT_ID }} + TENANT_ID: ${{ inputs.AZURE_TENANT_ID }} TEST_CLIENT_ID: ${{ inputs.AZURE_TEST_ACCESS_CLIENT_ID }} + NAME_PREFIX: ${{ inputs.AZURE_NAME_PREFIX }} KEY_VAULT_NAME: ${{ inputs.AZURE_ENVIRONMENT_KEY_VAULT_NAME }} MIGRATION_STORAGE_ACCOUNT_NAME: ${{ inputs.AZURE_MIGRATION_STORAGE_ACCOUNT_NAME }} - CLIENT_SECRET: ${{ inputs.AZURE_CLIENT_SECRET }} MASKINPORTEN_JWK: ${{ inputs.MASKINPORTEN_JWK }} MASKINPORTEN_CLIENT_ID: ${{ inputs.MASKINPORTEN_CLIENT_ID }} PLATFORM_SUBSCRIPTION_KEY: ${{ inputs.PLATFORM_SUBSCRIPTION_KEY }} diff --git a/.github/workflows/deploy-to-environment.yml b/.github/workflows/deploy-to-environment.yml index feb0b4c9..a1701f77 100644 --- a/.github/workflows/deploy-to-environment.yml +++ b/.github/workflows/deploy-to-environment.yml @@ -62,7 +62,6 @@ jobs: AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} AZURE_TEST_ACCESS_CLIENT_ID: ${{ secrets.AZURE_TEST_ACCESS_CLIENT_ID }} AZURE_MIGRATION_STORAGE_ACCOUNT_NAME: ${{ secrets.AZURE_MIGRATION_STORAGE_ACCOUNT_NAME }} - AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} MASKINPORTEN_JWK: ${{ secrets.MASKINPORTEN_JWK }} MASKINPORTEN_CLIENT_ID: ${{ secrets.MASKINPORTEN_CLIENT_ID }} PLATFORM_SUBSCRIPTION_KEY: ${{ secrets.PLATFORM_SUBSCRIPTION_KEY }} @@ -78,7 +77,6 @@ jobs: AZURE_ENVIRONMENT_KEY_VAULT_NAME: ${{ secrets.AZURE_ENVIRONMENT_KEY_VAULT_NAME }} AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - AZURE_OBJECT_ID: ${{ secrets.AZURE_OBJECT_ID }} AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} AZURE_MIGRATION_STORAGE_ACCOUNT_NAME: ${{ secrets.AZURE_MIGRATION_STORAGE_ACCOUNT_NAME }} @@ -92,5 +90,4 @@ jobs: AZURE_ENVIRONMENT_KEY_VAULT_NAME: ${{ secrets.AZURE_ENVIRONMENT_KEY_VAULT_NAME }} AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - AZURE_OBJECT_ID: ${{ secrets.AZURE_OBJECT_ID }} AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} diff --git a/README-infrastructure.md b/README-infrastructure.md index 2512ceb6..f1aaf00b 100644 --- a/README-infrastructure.md +++ b/README-infrastructure.md @@ -65,15 +65,10 @@ az ad app federated-credential create --id --parameters ## Manual steps after deployment to new environment -Get a client secret for the service principal that deploys and set the following key vault secret: -* AZURE_CLIENT_SECRET -Cannot be automated as our deploying service principal does not have access to its own secret - -Further, the following secrets has to be added to the keyVault: +The following secrets has to be added to the keyVault: 1. Platform-subscription key. See Step 0 in [technical integration guide](https://github.com/Altinn/altinn-broker/blob/main/docs/get-started.md) 2. maskinporten-client-id 3. maskinporten-jwk -4. deploy-client-secret # FAQ diff --git a/src/Altinn.Broker.API/Controllers/HealthController.cs b/src/Altinn.Broker.API/Controllers/HealthController.cs index 2a74bbac..ac46f07c 100644 --- a/src/Altinn.Broker.API/Controllers/HealthController.cs +++ b/src/Altinn.Broker.API/Controllers/HealthController.cs @@ -45,7 +45,7 @@ public async Task HealthCheckAsync() } // Verify that resource manager has access to our subscription - var credentials = new ClientSecretCredential(_azureResourceManagerOptions.TenantId, _azureResourceManagerOptions.ClientId, _azureResourceManagerOptions.ClientSecret); + var credentials = new DefaultAzureCredential(); var armClient = new ArmClient(credentials); var subscription = armClient.GetSubscriptionResource(new ResourceIdentifier($"/subscriptions/{_azureResourceManagerOptions.SubscriptionId}")); var resourceGroupCollection = subscription.GetResourceGroups(); @@ -54,7 +54,7 @@ public async Task HealthCheckAsync() { return BadRequest($"Resource groups not found under subscription with id: {subscription.Id}. Are the service principal environment variables set?"); } - await resourceGroupCollection.GetAsync($"altinn-{_azureResourceManagerOptions.Environment}-broker-rg"); + await resourceGroupCollection.GetAsync(_resourceManagerOptions.ApplicationResourceGroupName); return Ok("Environment properly configured"); } diff --git a/src/Altinn.Broker.Integrations/Azure/AzureResourceManagerOptions.cs b/src/Altinn.Broker.Integrations/Azure/AzureResourceManagerOptions.cs index bff0791e..60d65db3 100644 --- a/src/Altinn.Broker.Integrations/Azure/AzureResourceManagerOptions.cs +++ b/src/Altinn.Broker.Integrations/Azure/AzureResourceManagerOptions.cs @@ -7,9 +7,6 @@ public class AzureResourceManagerOptions public string Location { get; set; } [StringLength(7, ErrorMessage = "The environment can only be 7 characters long because of constraint on length of Azure storage account name")] public string Environment { get; set; } - public string? TenantId { get; set; } - public string? ClientId { get; set; } - public string? ClientSecret { get; set; } public string? SubscriptionId { get; set; } public string? ApplicationResourceGroupName { get; set; } public string? MalwareScanEventGridTopicName { get; set; } diff --git a/src/Altinn.Broker.Integrations/Azure/AzureResourceManagerService.cs b/src/Altinn.Broker.Integrations/Azure/AzureResourceManagerService.cs index 0c96bcef..8befc9fc 100644 --- a/src/Altinn.Broker.Integrations/Azure/AzureResourceManagerService.cs +++ b/src/Altinn.Broker.Integrations/Azure/AzureResourceManagerService.cs @@ -42,14 +42,7 @@ public AzureResourceManagerService(IOptions resourc { _resourceManagerOptions = resourceManagerOptions.Value; _hostEnvironment = hostingEnvironment; - if (string.IsNullOrWhiteSpace(_resourceManagerOptions.ClientId)) - { - _credentials = new DefaultAzureCredential(); - } - else - { - _credentials = new ClientSecretCredential(_resourceManagerOptions.TenantId, _resourceManagerOptions.ClientId, _resourceManagerOptions.ClientSecret); - } + _credentials = new DefaultAzureCredential(); _armClient = new ArmClient(_credentials); _serviceOwnerRepository = serviceOwnerRepository; _logger = logger; @@ -58,6 +51,7 @@ public AzureResourceManagerService(IOptions resourc public async Task Deploy(ServiceOwnerEntity serviceOwnerEntity, CancellationToken cancellationToken) { _logger.LogInformation($"Starting deployment for {serviceOwnerEntity.Name}"); + _logger.LogInformation($"Using app identity for deploying Azure resources"); // TODO remove var resourceGroupName = GetResourceGroupName(serviceOwnerEntity); var storageAccountName = GenerateStorageAccountName(); @@ -69,7 +63,6 @@ public async Task Deploy(ServiceOwnerEntity serviceOwnerEntity, CancellationToke var resourceGroupCollection = subscription.GetResourceGroups(); var resourceGroupData = new ResourceGroupData(_resourceManagerOptions.Location); resourceGroupData.Tags.Add("customer_id", serviceOwnerEntity.Id); - var resourceGroup = await resourceGroupCollection.CreateOrUpdateAsync(WaitUntil.Completed, resourceGroupName, resourceGroupData, cancellationToken); // Create or get the storage account From 5d84d0dbc0d190fb95aea511d19573c47ab29013 Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Wed, 22 May 2024 11:29:01 +0200 Subject: [PATCH 2/9] Fix build --- src/Altinn.Broker.API/Controllers/HealthController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Altinn.Broker.API/Controllers/HealthController.cs b/src/Altinn.Broker.API/Controllers/HealthController.cs index ac46f07c..bfc2d154 100644 --- a/src/Altinn.Broker.API/Controllers/HealthController.cs +++ b/src/Altinn.Broker.API/Controllers/HealthController.cs @@ -54,7 +54,7 @@ public async Task HealthCheckAsync() { return BadRequest($"Resource groups not found under subscription with id: {subscription.Id}. Are the service principal environment variables set?"); } - await resourceGroupCollection.GetAsync(_resourceManagerOptions.ApplicationResourceGroupName); + await resourceGroupCollection.GetAsync(_azureResourceManagerOptions.ApplicationResourceGroupName); return Ok("Environment properly configured"); } From 86bf3439dc4e1999c1f8efb9b606226b5a419b4f Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Wed, 22 May 2024 11:37:38 +0200 Subject: [PATCH 3/9] Remove extra required --- .github/actions/update-infrastructure/action.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/actions/update-infrastructure/action.yml b/.github/actions/update-infrastructure/action.yml index f8691fad..3f5a0568 100644 --- a/.github/actions/update-infrastructure/action.yml +++ b/.github/actions/update-infrastructure/action.yml @@ -24,7 +24,6 @@ inputs: AZURE_TENANT_ID: description: "Tenant ID for the service principal" required: true - required: true AZURE_TEST_ACCESS_CLIENT_ID: description: "Client ID for the test access service principal" required: true From 5d1183f9de94d41618c6cc57af5f71c291ff5317 Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Wed, 22 May 2024 12:04:09 +0200 Subject: [PATCH 4/9] Wrong resource group name --- .azure/applications/api/main.bicep | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.azure/applications/api/main.bicep b/.azure/applications/api/main.bicep index 99b421b9..de87a608 100644 --- a/.azure/applications/api/main.bicep +++ b/.azure/applications/api/main.bicep @@ -20,8 +20,9 @@ param namePrefix string var containerAppName = '${namePrefix}-app' +var resourceGroupName = '${namePrefix}-rg' resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: 'namePrefix-rg' + name: resourceGroupName location: location } From a4ff9129b6e32e0095577a8cd59cefeaeb0a8224 Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Wed, 22 May 2024 13:33:24 +0200 Subject: [PATCH 5/9] Need to separate into modules due to scoping --- .azure/applications/api/main.bicep | 11 +++++++++-- .azure/modules/identity/addContributorAccess.bicep | 13 +++++++++++++ .azure/modules/identity/create.bicep | 11 ----------- .github/workflows/ci-cd.yaml | 2 +- 4 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 .azure/modules/identity/addContributorAccess.bicep diff --git a/.azure/applications/api/main.bicep b/.azure/applications/api/main.bicep index de87a608..1ff3c71f 100644 --- a/.azure/applications/api/main.bicep +++ b/.azure/applications/api/main.bicep @@ -18,6 +18,7 @@ param keyVaultUrl string @secure() param namePrefix string +var image = 'ghcr.io/altinn/altinn-broker:${imageTag}' var containerAppName = '${namePrefix}-app' var resourceGroupName = '${namePrefix}-rg' @@ -26,7 +27,6 @@ resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { location: location } - module appIdentity '../../modules/identity/create.bicep' = { name: 'appIdentity' scope: resourceGroup @@ -36,6 +36,13 @@ module appIdentity '../../modules/identity/create.bicep' = { } } +module addContributorAccess '../../modules/identity/addContributorAccess.bicep' = { + name: 'appDeployToAzureAccess' + params: { + userAssignedIdentityPrincipalId: appIdentity.outputs.principalId + } +} + module keyVaultReaderAccessPolicyUserIdentity '../../modules/keyvault/addReaderRoles.bicep' = { name: 'kvreader-${namePrefix}-app' scope: resourceGroup @@ -71,7 +78,7 @@ module containerApp '../../modules/containerApp/main.bicep' = { dependsOn: [keyVaultReaderAccessPolicyUserIdentity, databaseAccess] params: { namePrefix: namePrefix - image: imageTag + image: image location: location environment: environment subscription_id: subscription().subscriptionId diff --git a/.azure/modules/identity/addContributorAccess.bicep b/.azure/modules/identity/addContributorAccess.bicep new file mode 100644 index 00000000..9f5c9858 --- /dev/null +++ b/.azure/modules/identity/addContributorAccess.bicep @@ -0,0 +1,13 @@ +targetScope = 'subscription' + +param userAssignedIdentityPrincipalId string + +var roleDefinitionResourceId = 'b24988ac-6180-42a0-ab88-20f7382dd24c' // Contributor role +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscription().id, userAssignedIdentityPrincipalId, roleDefinitionResourceId) + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionResourceId) + principalId: userAssignedIdentityPrincipalId + principalType: 'ServicePrincipal' + } +} diff --git a/.azure/modules/identity/create.bicep b/.azure/modules/identity/create.bicep index d70e17e1..14f1cdbf 100644 --- a/.azure/modules/identity/create.bicep +++ b/.azure/modules/identity/create.bicep @@ -7,17 +7,6 @@ resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@ name: '${namePrefix}-app-identity' location: location } - -var roleDefinitionResourceId = 'b24988ac-6180-42a0-ab88-20f7382dd24c' // Contributor role -resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(subscription().id, userAssignedIdentity.id, roleDefinitionResourceId) - properties: { - roleDefinitionId: roleDefinitionResourceId - principalId: userAssignedIdentity.id - principalType: 'ServicePrincipal' - } -} - output id string = userAssignedIdentity.id output clientId string = userAssignedIdentity.properties.clientId output principalId string = userAssignedIdentity.properties.principalId diff --git a/.github/workflows/ci-cd.yaml b/.github/workflows/ci-cd.yaml index 1b5ccd5d..3f16efc5 100644 --- a/.github/workflows/ci-cd.yaml +++ b/.github/workflows/ci-cd.yaml @@ -53,7 +53,7 @@ jobs: uses: ./.github/actions/publish-image with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - dockerImageBaseName: ghcr.io/ceredron/github-env-testing + dockerImageBaseName: ghcr.io/altinn/altinn-broker deploy-test: name: Internal test From 5ddd4db87f2066763ecde7cf24071b7cfde1cfdd Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Wed, 22 May 2024 13:43:01 +0200 Subject: [PATCH 6/9] Already in module --- .azure/infrastructure/main.bicep | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/.azure/infrastructure/main.bicep b/.azure/infrastructure/main.bicep index 61f1ce69..039c9098 100644 --- a/.azure/infrastructure/main.bicep +++ b/.azure/infrastructure/main.bicep @@ -55,25 +55,6 @@ resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { location: location } -resource StorageAccounts 'Microsoft.Security/pricings@2024-01-01' = { - name: 'StorageAccounts' - properties: { - pricingTier: 'Standard' - - subPlan: 'DefenderForStorageV2' - extensions: [ - { - name: 'OnUploadMalwareScanning' - isEnabled: 'True' - } - { - name: 'SensitiveDataDiscovery' - isEnabled: 'True' - } - ] - } -} - module environmentKeyVault '../modules/keyvault/create.bicep' = { scope: resourceGroup name: 'keyVault' From ff40f4db681dc933e363aaea70b61fd5e02f17be Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Wed, 22 May 2024 14:22:43 +0200 Subject: [PATCH 7/9] Add PLATFORM_BASE_URL as a environment secret --- .azure/applications/api/params.bicepparam | 2 +- .github/actions/release-version/action.yml | 12 ++++-------- .github/workflows/deploy-to-environment.yml | 1 + 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.azure/applications/api/params.bicepparam b/.azure/applications/api/params.bicepparam index feda2cd9..f1e23e0e 100644 --- a/.azure/applications/api/params.bicepparam +++ b/.azure/applications/api/params.bicepparam @@ -3,7 +3,7 @@ using './main.bicep' param namePrefix = readEnvironmentVariable('NAME_PREFIX') param location = 'norwayeast' param imageTag = readEnvironmentVariable('IMAGE_TAG') -param platform_base_url = 'https://platform.tt02.altinn.no/' +param platform_base_url = readEnvironmentVariable('PLATFORM_BASE_URL') param maskinporten_environment = 'ver2' param environment = readEnvironmentVariable('ENVIRONMENT') // secrets diff --git a/.github/actions/release-version/action.yml b/.github/actions/release-version/action.yml index a416cd66..323603a2 100644 --- a/.github/actions/release-version/action.yml +++ b/.github/actions/release-version/action.yml @@ -9,12 +9,6 @@ inputs: environment: description: "Github environment to deploy from" required: true - AZURE_CLIENT_ID: - description: "Client ID for the service principal" - required: true - AZURE_TENANT_ID: - description: "Tenant ID for the service principal" - required: true AZURE_SUBSCRIPTION_ID: description: "Subscription ID for the service principal" required: true @@ -24,6 +18,9 @@ inputs: AZURE_NAME_PREFIX: description: "Prefix for all resources" required: true + PLATFORM_BASE_URL: + description: "Base url for Altinn platform" + required: true runs: using: "composite" @@ -51,8 +48,7 @@ runs: KEY_VAULT_NAME: ${{ inputs.AZURE_ENVIRONMENT_KEY_VAULT_NAME }} KEY_VAULT_URL: https://${{ inputs.AZURE_ENVIRONMENT_KEY_VAULT_NAME }}.vault.azure.net NAME_PREFIX: ${{ inputs.AZURE_NAME_PREFIX }} - CLIENT_ID: ${{ inputs.AZURE_CLIENT_ID }} - TENANT_ID: ${{ inputs.AZURE_TENANT_ID }} + PLATFORM_BASE_URL: ${{ inputs.PLATFORM_BASE_URL }} with: scope: subscription subscriptionId: ${{ inputs.AZURE_SUBSCRIPTION_ID }} diff --git a/.github/workflows/deploy-to-environment.yml b/.github/workflows/deploy-to-environment.yml index a1701f77..89c703db 100644 --- a/.github/workflows/deploy-to-environment.yml +++ b/.github/workflows/deploy-to-environment.yml @@ -91,3 +91,4 @@ jobs: AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + PLATFORM_BASE_URL: ${{ secrets.PLATFORM_BASE_URL }} From ae0084b2aba6f1804701ea4122cb65a9f0186208 Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Wed, 22 May 2024 14:24:46 +0200 Subject: [PATCH 8/9] Now unused --- .github/workflows/deploy-to-environment.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/deploy-to-environment.yml b/.github/workflows/deploy-to-environment.yml index 89c703db..4a98a0b5 100644 --- a/.github/workflows/deploy-to-environment.yml +++ b/.github/workflows/deploy-to-environment.yml @@ -88,7 +88,5 @@ jobs: environment: ${{ inputs.environment }} AZURE_NAME_PREFIX: ${{ secrets.AZURE_NAME_PREFIX }} AZURE_ENVIRONMENT_KEY_VAULT_NAME: ${{ secrets.AZURE_ENVIRONMENT_KEY_VAULT_NAME }} - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} PLATFORM_BASE_URL: ${{ secrets.PLATFORM_BASE_URL }} From 780e65d629e36001db3fee1ee7674ec863f72b27 Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Wed, 22 May 2024 14:33:28 +0200 Subject: [PATCH 9/9] No need for this permission anymore as we no longer migrate from pipeline --- .azure/infrastructure/main.bicep | 3 -- .azure/infrastructure/params.bicepparam | 1 - .azure/modules/keyvault/create.bicep | 32 +------------------ .../actions/update-infrastructure/action.yml | 1 - 4 files changed, 1 insertion(+), 36 deletions(-) diff --git a/.azure/infrastructure/main.bicep b/.azure/infrastructure/main.bicep index 039c9098..8b28d6c7 100644 --- a/.azure/infrastructure/main.bicep +++ b/.azure/infrastructure/main.bicep @@ -8,8 +8,6 @@ param sourceKeyVaultName string @secure() param tenantId string @secure() -param azureClientId string -@secure() param test_client_id string param environment string @secure() @@ -64,7 +62,6 @@ module environmentKeyVault '../modules/keyvault/create.bicep' = { sku: keyVaultSku tenant_id: tenantId environment: environment - azureClientId: azureClientId test_client_id: test_client_id } } diff --git a/.azure/infrastructure/params.bicepparam b/.azure/infrastructure/params.bicepparam index cc65bc54..f97450b9 100644 --- a/.azure/infrastructure/params.bicepparam +++ b/.azure/infrastructure/params.bicepparam @@ -7,7 +7,6 @@ param environment = readEnvironmentVariable('ENVIRONMENT') // secrets param brokerPgAdminPassword = readEnvironmentVariable('BROKER_PG_ADMIN_PASSWORD') param tenantId = readEnvironmentVariable('TENANT_ID') -param azureClientId = readEnvironmentVariable('CLIENT_ID') param test_client_id = readEnvironmentVariable('TEST_CLIENT_ID') param sourceKeyVaultName = readEnvironmentVariable('KEY_VAULT_NAME') param migrationsStorageAccountName = readEnvironmentVariable('MIGRATION_STORAGE_ACCOUNT_NAME') diff --git a/.azure/modules/keyvault/create.bicep b/.azure/modules/keyvault/create.bicep index 58d0fdb4..4aaba225 100644 --- a/.azure/modules/keyvault/create.bicep +++ b/.azure/modules/keyvault/create.bicep @@ -5,8 +5,6 @@ param environment string param tenant_id string @secure() param test_client_id string -@secure() -param azureClientId string @export() type Sku = { name: 'standard' @@ -25,19 +23,6 @@ resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = { tenantId: tenant_id accessPolicies: environment == 'test' ? [ - { - applicationId: null - tenantId: tenant_id - objectId: azureClientId - permissions: { - keys: [] - secrets: [ - 'Get' - 'List' - ] - certificates: [] - } - } { applicationId: null tenantId: tenant_id @@ -52,22 +37,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = { certificates: [] } } - ] - : [ - { - applicationId: null - tenantId: tenant_id - objectId: azureClientId - permissions: { - keys: [] - secrets: [ - 'Get' - 'List' - ] - certificates: [] - } - } - ] + ]: [] } } diff --git a/.github/actions/update-infrastructure/action.yml b/.github/actions/update-infrastructure/action.yml index 3f5a0568..693b8864 100644 --- a/.github/actions/update-infrastructure/action.yml +++ b/.github/actions/update-infrastructure/action.yml @@ -78,7 +78,6 @@ runs: BROKER_PG_ADMIN_PASSWORD: ${{ steps.pwd-generator.outputs.postgresqlPassword }} AZURE_NAME_PREFIX: ${{ inputs.AZURE_NAME_PREFIX }} SOURCE_KEY_VAULT_NAME: ${{ inputs.AZURE_ENVIRONMENT_KEY_VAULT_NAME }} - CLIENT_ID: ${{ inputs.AZURE_CLIENT_ID }} TENANT_ID: ${{ inputs.AZURE_TENANT_ID }} TEST_CLIENT_ID: ${{ inputs.AZURE_TEST_ACCESS_CLIENT_ID }} NAME_PREFIX: ${{ inputs.AZURE_NAME_PREFIX }}