mq-quiz / infra /main.bicep
Pamela Fox
Use postgres DB for permission reasons
d609fe2
targetScope = 'subscription'
@minLength(1)
@maxLength(64)
@description('Name which is used to generate a short unique hash for each resource')
param name string
@minLength(1)
@description('Primary location for all resources')
param location string
@description('Entra admin role name')
param postgresEntraAdministratorName string
@description('Entra admin role object ID (in Entra)')
param postgresEntraAdministratorObjectId string
@description('Entra admin user type')
@allowed([
'User'
'Group'
'ServicePrincipal'
])
param postgresEntraAdministratorType string = 'User'
@description('Id of the user or app to assign application roles')
param principalId string = ''
@secure()
@description('Django SECRET_KEY for cryptographic signing')
param djangoSecretKey string
@description('Running on GitHub Actions?')
param runningOnGh bool = false
// Necessary for post-provision script, can be disabled after
@description('Allow all IPs to connect to the PostgreSQL server')
param postgresAllowAllIPs bool = true
var resourceToken = toLower(uniqueString(subscription().id, name, location))
var tags = { 'azd-env-name': name }
resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
name: '${name}-rg'
location: location
tags: tags
}
var prefix = '${name}-${resourceToken}'
var postgresServerName = '${prefix}-postgresql'
var postgresDatabaseName = 'postgres'
module postgresServer 'core/database/postgresql/flexibleserver.bicep' = {
name: 'postgresql'
scope: resourceGroup
params: {
name: postgresServerName
location: location
tags: tags
sku: {
name: 'Standard_B1ms'
tier: 'Burstable'
}
storage: {
storageSizeGB: 32
}
version: '16'
authType: 'EntraOnly'
entraAdministratorName: postgresEntraAdministratorName
entraAdministratorObjectId: postgresEntraAdministratorObjectId
entraAdministratorType: postgresEntraAdministratorType
allowAzureIPsFirewall: true
allowAllIPsFirewall: postgresAllowAllIPs
}
}
var webAppName = '${prefix}-app-service'
module web 'core/host/appservice.bicep' = {
name: 'appservice'
scope: resourceGroup
params: {
name: webAppName
location: location
tags: union(tags, { 'azd-service-name': 'web' })
appServicePlanId: appServicePlan.outputs.id
runtimeName: 'python'
runtimeVersion: '3.11'
scmDoBuildDuringDeployment: true
ftpsState: 'Disabled'
managedIdentity: true
appCommandLine: 'python manage.py migrate && gunicorn --workers 2 --threads 4 --timeout 60 --access-logfile \'-\' --error-logfile \'-\' --bind=0.0.0.0:8000 --chdir=/home/site/wwwroot quizsite.wsgi'
appSettings: {
ADMIN_URL: 'admin${uniqueString(appServicePlan.outputs.id)}'
DBENGINE: 'django.db.backends.postgresql'
DBHOST: postgresServer.outputs.POSTGRES_DOMAIN_NAME
DBNAME: postgresDatabaseName
DBUSER: webAppName
DBSSL: 'require'
STATIC_BACKEND: 'whitenoise.storage.CompressedManifestStaticFilesStorage'
SECRET_KEY: '@Microsoft.KeyVault(VaultName=${keyVault.outputs.name};SecretName=djangoSecretKey)'
}
}
}
module appServicePlan 'core/host/appserviceplan.bicep' = {
name: 'serviceplan'
scope: resourceGroup
params: {
name: '${prefix}-serviceplan'
location: location
tags: tags
sku: {
name: 'B1'
}
reserved: true
}
}
module webKeyVaultAccess 'core/security/keyvault-access.bicep' = {
name: 'web-keyvault-access'
scope: resourceGroup
params: {
keyVaultName: keyVault.outputs.name
principalId: web.outputs.identityPrincipalId
}
}
// Store secrets in a keyvault
module keyVault './core/security/keyvault.bicep' = {
name: 'keyvault'
scope: resourceGroup
params: {
name: '${take(replace(prefix, '-', ''), 17)}-vault'
location: location
tags: tags
}
}
module userKeyVaultAccess 'core/security/role.bicep' = {
name: 'user-keyvault-access'
scope: resourceGroup
params: {
principalId: principalId
principalType: runningOnGh ? 'ServicePrincipal' : 'User'
roleDefinitionId: '00482a5a-887f-4fb3-b363-3b7fe8e74483'
}
}
module backendKeyVaultAccess 'core/security/role.bicep' = {
name: 'backend-keyvault-access'
scope: resourceGroup
params: {
principalId: web.outputs.identityPrincipalId
principalType: 'ServicePrincipal'
roleDefinitionId: '00482a5a-887f-4fb3-b363-3b7fe8e74483'
}
}
var secrets = [
{
name: 'djangoSecretKey'
value: djangoSecretKey
}
]
@batchSize(1)
module keyVaultSecrets './core/security/keyvault-secret.bicep' = [
for secret in secrets: {
name: 'keyvault-secret-${secret.name}'
scope: resourceGroup
params: {
keyVaultName: keyVault.outputs.name
name: secret.name
secretValue: secret.value
}
}
]
module logAnalyticsWorkspace 'core/monitor/loganalytics.bicep' = {
name: 'loganalytics'
scope: resourceGroup
params: {
name: '${prefix}-loganalytics'
location: location
tags: tags
}
}
output WEB_APP_NAME string = webAppName
output WEB_URI string = 'https://${web.outputs.uri}'
output SERVICE_WEB_IDENTITY_NAME string = webAppName
output AZURE_LOCATION string = location
output AZURE_KEY_VAULT_NAME string = keyVault.outputs.name
output POSTGRES_HOST string = postgresServer.outputs.POSTGRES_DOMAIN_NAME
output POSTGRES_USERNAME string = postgresEntraAdministratorName
output POSTGRES_ALLOW_ALL_IPS bool = postgresAllowAllIPs