File size: 5,433 Bytes
80db45a f24be86 fb79ec6 80db45a f24be86 b3a3223 80db45a 9595e1d d609fe2 9595e1d b3a3223 f24be86 fb79ec6 b3a3223 9595e1d f24be86 9595e1d f24be86 9595e1d 4dec878 9595e1d 5f87718 4dec878 f194cdb fb79ec6 f24be86 4dec878 886a656 fb79ec6 9595e1d 669c0b8 fb79ec6 f24be86 fb79ec6 f24be86 fb79ec6 aef59ad fb79ec6 aef59ad f24be86 9595e1d f24be86 9595e1d f24be86 80db45a f24be86 b3a3223 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
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
|