Skip to content

Commit

Permalink
Merge pull request #5222 from dfe-analytical-services/EES-5479-modula…
Browse files Browse the repository at this point in the history
…rise-bicep

Ees 5479 modularise bicep
  • Loading branch information
duncan-at-hiveit committed Sep 19, 2024
2 parents 7e0661a + 2f415ec commit 728a7f3
Show file tree
Hide file tree
Showing 42 changed files with 1,379 additions and 909 deletions.
2 changes: 1 addition & 1 deletion infrastructure/parameters/test.parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
"value": true
},
"publicDataDbExists": {
"value": false
"value": true
}
}
}
19 changes: 19 additions & 0 deletions infrastructure/templates/public-api/abbreviations.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Originally sourced from https://github.com/Azure-Samples/todo-csharp-sql/blob/main/infra/abbreviations.json.
@export()
var abbreviations = {
appContainerApps: 'ca'
appManagedEnvironments: 'cae'
// TODO - remove the "-flexibleserver" suffix and change the suffix of our PSQL instance to "-01"
dBforPostgreSQLServers: 'psql-flexibleserver'
// 'ai' is non-standard - it should be 'appi'
insightsComponents: 'ai'
managedIdentityUserAssignedIdentities: 'id'
networkApplicationGateways: 'agw'
operationalInsightsWorkspaces: 'log'
// 'sa' is non-standard - it should be 'st'
storageStorageAccounts: 'sa'
// 'fa' is non-standard - it shoule be 'func'
webSitesFunctions: 'fa'
// 'asp' is non-standard - it should be 'plan'
webServerFarms: 'asp'
}
74 changes: 37 additions & 37 deletions infrastructure/templates/public-api/api-infrastructure-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ resources:
variables:
- group: Public API Infrastructure - common
- name: isDev
value: $[eq(variables['Build.SourceBranch'], 'refs/heads/dev')]
value: $[eq(variables['Build.SourceBranch'], 'refs/heads/EES-5479-modularise-bicep')]
- name: isTest
value: $[eq(variables['Build.SourceBranch'], 'refs/heads/test')]
- name: isMaster
Expand Down Expand Up @@ -53,41 +53,41 @@ pool:
vmImage: $(vmImageName)

stages:
- template: validate-stage-template.yml
parameters:
stageName: 'Validate_Against_Development'
condition: eq(variables.isDev, true)
environment: 'Development'
serviceConnection: $(serviceConnectionDevelopment)
parameterFile: $(devParamFile)
- template: validate-stage-template.yml
parameters:
stageName: 'Validate_Against_Development'
condition: eq(variables.isDev, true)
environment: 'Development'
serviceConnection: $(serviceConnectionDevelopment)
parameterFile: $(devParamFile)

- template: deploy-stage-template.yml
parameters:
stageName: 'Deploy_to_Development'
condition: and(not(or(failed(), canceled())), eq(variables.isDev, true))
dependsOn: 'Validate_Against_Development'
environment: 'Development'
serviceConnection: $(serviceConnectionDevelopment)
subscription: $(subscription)
parameterFile: $(devParamFile)

- template: deploy-stage-template.yml
parameters:
stageName: 'Deploy_to_Development'
condition: and(succeeded(), eq(variables.isDev, true))
dependsOn: 'Validate_Against_Development'
environment: 'Development'
serviceConnection: $(serviceConnectionDevelopment)
subscription: $(subscription)
parameterFile: $(devParamFile)
- template: validate-stage-template.yml
parameters:
stageName: 'Validate_Against_Test'
condition: eq(variables.isTest, true)
environment: 'Test'
serviceConnection: $(serviceConnectionTest)
parameterFile: $(testParamFile)

- template: validate-stage-template.yml
parameters:
stageName: 'Validate_Against_Test'
condition: eq(variables.isTest, true)
environment: 'Test'
serviceConnection: $(serviceConnectionTest)
parameterFile: $(testParamFile)

- template: deploy-stage-template.yml
parameters:
stageName: 'Deploy_to_Test'
dependsOn: 'Validate_Against_Test'
condition: and(succeeded(), eq(variables.isTest, true))
environment: 'Test'
serviceConnection: $(serviceConnectionTest)
subscription: $(subscription)
parameterFile: $(testParamFile)
- template: deploy-stage-template.yml
parameters:
stageName: 'Deploy_to_Test'
dependsOn: 'Validate_Against_Test'
condition: and(not(or(failed(), canceled())), eq(variables.isTest, true))
environment: 'Test'
serviceConnection: $(serviceConnectionTest)
subscription: $(subscription)
parameterFile: $(testParamFile)

# - template: validate-stage-template.yml
# parameters:
Expand All @@ -100,7 +100,7 @@ stages:
# - template: deploy-stage-template.yml
# parameters:
# stageName: 'Deploy_to_PreProduction'
# condition: and(succeeded(), eq(variables.isMaster, true))
# condition: and(not(or(failed('Validate_Against_PreProduction'), canceled('Validate_Against_PreProduction')), eq(variables.isMaster, true))
# dependsOn: 'Validate_Against_PreProduction'
# environment: 'Pre-production'
# serviceConnection: $(serviceConnectionPreProduction)
Expand All @@ -110,15 +110,15 @@ stages:
# - template: validate-stage-template.yml
# parameters:
# stageName: 'Validate_Against_Production'
# condition: and(succeeded(), eq(variables.isMaster, true))
# condition: and(not(or(failed('Deploy_to_PreProduction'), canceled('Deploy_to_PreProduction')), eq(variables.isMaster, true))
# environment: 'Production'
# serviceConnection: $(serviceConnectionProduction)
# parameterFile: $(prodParamFile)
#
# - template: deploy-stage-template.yml
# parameters:
# stageName: 'Deploy_to_Production'
# condition: and(succeeded(), eq(variables.isMaster, true))
# condition: and(not(or(failed('Validate_Against_Production'), canceled('Validate_Against_Production')), eq(variables.isMaster, true))
# dependsOn: 'Validate_Against_Production'
# environment: 'Production'
# serviceConnection: $(serviceConnectionProduction)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { resourceNamesType } from '../../types.bicep'

@description('Specifies common resource naming variables.')
param resourceNames resourceNamesType

@description('Specifies the location for all resources.')
param location string

@description('Specifies the id of the Container App Environment in which to deploy this Container App.')
param containerAppEnvironmentId string

@description('The tags of the Docker images to deploy.')
param dockerImagesTag string

@description('The URL of the Public API.')
param publicApiUrl string

@description('The URL of the Content API.')
param contentApiUrl string

@description('Specifies the Application (Client) Id of the App Registration used to represent the API Container App.')
param apiAppRegistrationClientId string

@description('Specifies the Application Insights connection string for this Container App to use for its monitoring.')
param appInsightsConnectionString string

@description('Specifies a set of tags with which to tag the resource in Azure.')
param tagValues object

var dataFilesFileShareMountPath = '/data/public-api-data'

resource adminAppService 'Microsoft.Web/sites@2023-12-01' existing = {
name: resourceNames.existingResources.adminApp
}

resource adminAppServiceIdentity 'Microsoft.ManagedIdentity/identities@2023-01-31' existing = {
scope: adminAppService
name: 'default'
}

var adminAppClientId = adminAppServiceIdentity.properties.clientId
var adminAppPrincipalId = adminAppServiceIdentity.properties.principalId

resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
name: resourceNames.existingResources.keyVault
}

resource apiContainerAppManagedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = {
name: resourceNames.publicApi.apiAppIdentity
}

module apiContainerAppModule '../../components/containerApp.bicep' = {
name: 'apiContainerAppDeploy'
params: {
location: location
containerAppName: resourceNames.publicApi.apiApp
acrLoginServer: keyVault.getSecret('DOCKER-REGISTRY-SERVER-DOMAIN')
containerAppImageName: 'ees-public-api/api:${dockerImagesTag}'
dockerPullManagedIdentityClientId: keyVault.getSecret('DOCKER-REGISTRY-SERVER-USERNAME')
dockerPullManagedIdentitySecretValue: keyVault.getSecret('DOCKER-REGISTRY-SERVER-PASSWORD')
userAssignedManagedIdentityId: apiContainerAppManagedIdentity.id
managedEnvironmentId: containerAppEnvironmentId
corsPolicy: {
allowedOrigins: [
publicApiUrl
'http://localhost:3000'
'http://127.0.0.1'
]
}
volumeMounts: [
{
volumeName: 'public-api-fileshare-mount'
mountPath: dataFilesFileShareMountPath
}
]
volumes: [
{
name: 'public-api-fileshare-mount'
storageType: 'AzureFile'
storageName: resourceNames.publicApi.publicApiFileshare
}
]
appSettings: [
{
name: 'ConnectionStrings__PublicDataDb'
value: 'Server=${resourceNames.sharedResources.postgreSqlFlexibleServer}.postgres.database.azure.com;Database=public_data;Port=5432;User Id=${resourceNames.publicApi.apiAppIdentity}'
}
{
// This settings allows the Container App to identify which user-assigned identity it should use in order to
// perform Managed Identity-based authentication and authorization with other Azure services / resources.
//
// It is used in conjunction with the Azure.Identity .NET library to retrieve access tokens for the user-assigned
// identity.
name: 'AZURE_CLIENT_ID'
value: apiContainerAppManagedIdentity.properties.clientId
}
{
name: 'ContentApi__Url'
value: contentApiUrl
}
{
name: 'MiniProfiler__Enabled'
value: 'true'
}
{
name: 'DataFiles__BasePath'
value: dataFilesFileShareMountPath
}
{
name: 'OpenIdConnect__TenantId'
value: tenant().tenantId
}
{
name: 'OpenIdConnect__ClientId'
value: apiAppRegistrationClientId
}
{
name: 'ApplicationInsights__ConnectionString'
value: appInsightsConnectionString
}
]
entraIdAuthentication: {
appRegistrationClientId: apiAppRegistrationClientId
allowedClientIds: [
adminAppClientId
]
allowedPrincipalIds: [
adminAppPrincipalId
]
requireAuthentication: false
}
tagValues: tagValues
}
}

output containerAppFqdn string = apiContainerAppModule.outputs.containerAppFqdn
output containerAppName string = apiContainerAppModule.outputs.containerAppName
output containerAppHealthProbeRelativeUrl string = '/docs'
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { resourceNamesType } from '../../types.bicep'

@description('Specifies common resource naming variables.')
param resourceNames resourceNamesType

@description('Specifies the location for all resources.')
param location string

@description('Specifies a set of tags with which to tag the resource in Azure.')
param tagValues object

resource apiContainerAppManagedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
name: resourceNames.publicApi.apiAppIdentity
location: location
tags: tagValues
}

// TODO - commenting out for now, as we can't apply roles to Container Registries in other Resource Groups.
// When we have a shared Resource Group for our ACR with special privileges, we can start to use the Container App
// Identity again to pull Docker images, but for now we continue to use our shared SPN.
// module apiContainerAppAcrPullRoleAssignmentModule '../../components/containerRegistryRoleAssignment.bicep' = {
// name: '${resourceNames.publicApi.apiAppIdentity}AcrPullRoleAssignmentDeploy'
// scope: resourceGroup(resourceNames.existingResources.acrResourceGroup)
// params: {
// role: 'AcrPull'
// containerRegistryName: resourceNames.existingResources.acr
// principalIds: [apiContainerAppManagedIdentity.properties.principalId]
// }
// }
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { resourceNamesType } from '../../types.bicep'

@description('Specifies common resource naming variables.')
param resourceNames resourceNamesType

@description('Specifies the location for all resources.')
param location string

module applicationInsightsModule '../../components/appInsights.bicep' = {
name: 'appInsightsDeploy'
params: {
location: location
appInsightsName: resourceNames.publicApi.appInsights
}
}

output appInsightsName string = resourceNames.publicApi.appInsights
output appInsightsKey string = applicationInsightsModule.outputs.applicationInsightsKey
output appInsightsConnectionString string = applicationInsightsModule.outputs.applicationInsightsConnectionString
Loading

0 comments on commit 728a7f3

Please sign in to comment.