Pamela Fox
commited on
Commit
·
fb79ec6
1
Parent(s):
eb6044e
Change infrastructure
Browse files- .gitattributes +3 -0
- .pre-commit-config.yaml +0 -2
- README.md +36 -13
- infra/core/database/postgresql/flexibleserver.bicep +28 -15
- infra/core/host/appservice.bicep +3 -13
- infra/main.bicep +61 -26
- infra/main.parameters.json +11 -2
- pyproject.toml +6 -6
.gitattributes
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
* text=auto eol=lf
|
2 |
+
*.{cmd,[cC][mM][dD]} text eol=crlf
|
3 |
+
*.{bat,[bB][aA][tT]} text eol=crlf
|
.pre-commit-config.yaml
CHANGED
@@ -9,9 +9,7 @@ repos:
|
|
9 |
rev: 22.3.0
|
10 |
hooks:
|
11 |
- id: black
|
12 |
-
args: ['--config=./pyproject.toml']
|
13 |
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
14 |
rev: v0.0.121
|
15 |
hooks:
|
16 |
- id: ruff
|
17 |
-
exclude: '.venv/'
|
|
|
9 |
rev: 22.3.0
|
10 |
hooks:
|
11 |
- id: black
|
|
|
12 |
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
13 |
rev: v0.0.121
|
14 |
hooks:
|
15 |
- id: ruff
|
|
README.md
CHANGED
@@ -3,25 +3,35 @@
|
|
3 |
# Quizzes app
|
4 |
|
5 |
An example Django app that serves quizzes and lets people know how they scored.
|
6 |
-
Quizzes and their questions are stored in a
|
7 |
There is no user authentication or per-user data stored.
|
8 |
|
9 |
-
##
|
|
|
|
|
10 |
|
11 |
-
|
12 |
|
13 |
-
|
14 |
-
then it's best to first [create a Python virtual environment](https://docs.python.org/3/tutorial/venv.html#creating-virtual-environments) and activate that.
|
15 |
|
16 |
-
|
17 |
|
18 |
```shell
|
19 |
python3 -m pip install -r requirements-dev.txt
|
20 |
```
|
21 |
|
22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
|
24 |
-
|
25 |
|
26 |
```shell
|
27 |
python -c 'import secrets; print(secrets.token_hex())'
|
@@ -43,7 +53,7 @@ then it's best to first [create a Python virtual environment](https://docs.pytho
|
|
43 |
|
44 |
### Admin
|
45 |
|
46 |
-
This app comes with the built-in Django admin.
|
47 |
|
48 |
1. Create a superuser:
|
49 |
|
@@ -86,7 +96,7 @@ azd up
|
|
86 |
python manage.py createsuperuser
|
87 |
```
|
88 |
|
89 |
-
|
90 |
|
91 |
This project includes a Github workflow for deploying the resources to Azure
|
92 |
on every push to main. That workflow requires several Azure-related authentication secrets
|
@@ -96,21 +106,34 @@ to be stored as Github action secrets. To set that up, run:
|
|
96 |
azd pipeline config
|
97 |
```
|
98 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
### Costs
|
100 |
|
101 |
Pricing varies per region and usage, so it isn't possible to predict exact costs for your usage.
|
102 |
|
103 |
-
You can try the Azure pricing calculator for the resources:
|
104 |
|
105 |
- Azure App Service: Basic Tier with 1 CPU core, 1.75GB RAM. Pricing is hourly. [Pricing](https://azure.microsoft.com/pricing/details/app-service/linux/)
|
106 |
- PostgreSQL Flexible Server: Burstable Tier with 1 CPU core, 32GB storage. Pricing is hourly. [Pricing](https://azure.microsoft.com/pricing/details/postgresql/flexible-server/)
|
107 |
-
-
|
108 |
-
- Private DNS Zone: Pricing based on number of zones per region per month. [Pricing](https://azure.microsoft.com/en-in/pricing/details/dns/)
|
109 |
- Log analytics: Pay-as-you-go tier. Costs based on data ingested. [Pricing](https://azure.microsoft.com/pricing/details/monitor/)
|
110 |
|
111 |
⚠�� To avoid unnecessary costs, remember to take down your app if it's no longer in use,
|
112 |
either by deleting the resource group in the Portal or running `azd down`.
|
113 |
|
|
|
114 |
## Getting help
|
115 |
|
116 |
If you're working with this project and running into issues, please post in **Discussions**.
|
|
|
3 |
# Quizzes app
|
4 |
|
5 |
An example Django app that serves quizzes and lets people know how they scored.
|
6 |
+
Quizzes and their questions are stored in a PostgreSQL database.
|
7 |
There is no user authentication or per-user data stored.
|
8 |
|
9 |
+
## Opening the project
|
10 |
+
|
11 |
+
This project has [Dev Container support](https://code.visualstudio.com/docs/devcontainers/containers), so it will be be setup automatically if you open it in Github Codespaces or in local VS Code with the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers).
|
12 |
|
13 |
+
If you're not using one of those options for opening the project, then you'll need to:
|
14 |
|
15 |
+
1. Create a [Python virtual environment](https://docs.python.org/3/tutorial/venv.html#creating-virtual-environments) and activate it.
|
|
|
16 |
|
17 |
+
2. Install the requirements:
|
18 |
|
19 |
```shell
|
20 |
python3 -m pip install -r requirements-dev.txt
|
21 |
```
|
22 |
|
23 |
+
3. Install the pre-commit hooks:
|
24 |
+
|
25 |
+
```shell
|
26 |
+
pre-commit install
|
27 |
+
```
|
28 |
+
|
29 |
+
## Local development
|
30 |
+
|
31 |
+
|
32 |
+
1. Create an `.env` file using `.env.sample` as a guide. Set the value of `DBNAME` to the name of an existing database in your local PostgreSQL instance. Set the values of `DBHOST`, `DBUSER`, and `DBPASS` as appropriate for your local PostgreSQL instance. If you're in the devcontainer, copy the values exactly from `.env.sample`.
|
33 |
|
34 |
+
2. Fill in a secret value for `SECRET_KEY`. You can use this command to generate an appropriate value.
|
35 |
|
36 |
```shell
|
37 |
python -c 'import secrets; print(secrets.token_hex())'
|
|
|
53 |
|
54 |
### Admin
|
55 |
|
56 |
+
This app comes with the built-in Django admin interface.
|
57 |
|
58 |
1. Create a superuser:
|
59 |
|
|
|
96 |
python manage.py createsuperuser
|
97 |
```
|
98 |
|
99 |
+
### CI/CD pipeline
|
100 |
|
101 |
This project includes a Github workflow for deploying the resources to Azure
|
102 |
on every push to main. That workflow requires several Azure-related authentication secrets
|
|
|
106 |
azd pipeline config
|
107 |
```
|
108 |
|
109 |
+
## Security
|
110 |
+
|
111 |
+
It is important to secure the databases in web applications to prevent unwanted data access.
|
112 |
+
This infrastructure uses the following mechanisms to secure the PostgreSQL database:
|
113 |
+
|
114 |
+
* Azure Firewall: The database is accessible only from other Azure IPs, not from public IPs. (Note that includes other customers using Azure).
|
115 |
+
* Admin Username: Randomly generated and stored in Key Vault.
|
116 |
+
* Admin Password: Randomly generated and stored in Key Vault.
|
117 |
+
* PostgreSQL Version: Latest available on Azure, version 14, which includes security improvements.
|
118 |
+
|
119 |
+
⚠️ For even more security, consider using an Azure Virtual Network to connect the Web App to the Database.
|
120 |
+
See [the Django-on-Azure project](https://github.com/tonybaloney/django-on-azure) for example infrastructure files.
|
121 |
+
|
122 |
### Costs
|
123 |
|
124 |
Pricing varies per region and usage, so it isn't possible to predict exact costs for your usage.
|
125 |
|
126 |
+
You can try the [Azure pricing calculator](https://azure.com/e/560b5f259111424daa7eb23c6848d164) for the resources:
|
127 |
|
128 |
- Azure App Service: Basic Tier with 1 CPU core, 1.75GB RAM. Pricing is hourly. [Pricing](https://azure.microsoft.com/pricing/details/app-service/linux/)
|
129 |
- PostgreSQL Flexible Server: Burstable Tier with 1 CPU core, 32GB storage. Pricing is hourly. [Pricing](https://azure.microsoft.com/pricing/details/postgresql/flexible-server/)
|
130 |
+
- Key Vault: Standard tier. Costs are per transaction, a few transactions are used on each deploy. [Pricing](https://azure.microsoft.com/pricing/details/key-vault/)
|
|
|
131 |
- Log analytics: Pay-as-you-go tier. Costs based on data ingested. [Pricing](https://azure.microsoft.com/pricing/details/monitor/)
|
132 |
|
133 |
⚠�� To avoid unnecessary costs, remember to take down your app if it's no longer in use,
|
134 |
either by deleting the resource group in the Portal or running `azd down`.
|
135 |
|
136 |
+
|
137 |
## Getting help
|
138 |
|
139 |
If you're working with this project and running into issues, please post in **Discussions**.
|
infra/core/database/postgresql/flexibleserver.bicep
CHANGED
@@ -4,20 +4,19 @@ param tags object = {}
|
|
4 |
|
5 |
param sku object
|
6 |
param storage object
|
7 |
-
param delegatedSubnetResourceId string = ''
|
8 |
-
param privateDnsZoneArmResourceId string = ''
|
9 |
-
param privateDnsZoneLink object = {}
|
10 |
-
|
11 |
-
param databaseName string
|
12 |
param administratorLogin string
|
13 |
@secure()
|
14 |
param administratorLoginPassword string
|
|
|
|
|
|
|
|
|
15 |
|
16 |
// PostgreSQL version
|
17 |
-
@allowed(['11', '12', '13', '14', '15'])
|
18 |
param version string
|
19 |
|
20 |
-
|
|
|
21 |
location: location
|
22 |
tags: tags
|
23 |
name: name
|
@@ -27,25 +26,39 @@ resource postgresServer 'Microsoft.DBforPostgreSQL/flexibleServers@2022-01-20-pr
|
|
27 |
administratorLogin: administratorLogin
|
28 |
administratorLoginPassword: administratorLoginPassword
|
29 |
storage: storage
|
30 |
-
network: union(
|
31 |
-
!empty(delegatedSubnetResourceId) ? { delegatedSubnetResourceId: delegatedSubnetResourceId } : {},
|
32 |
-
!empty(privateDnsZoneArmResourceId) ? {privateDnsZoneArmResourceId: privateDnsZoneArmResourceId } : {})
|
33 |
highAvailability: {
|
34 |
mode: 'Disabled'
|
35 |
}
|
36 |
}
|
37 |
|
38 |
-
resource database 'databases' = {
|
39 |
-
name:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
}
|
41 |
|
42 |
-
resource
|
43 |
-
name: '
|
44 |
properties: {
|
45 |
startIpAddress: '0.0.0.0'
|
46 |
endIpAddress: '0.0.0.0'
|
47 |
}
|
48 |
}
|
49 |
|
50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
}
|
|
|
|
|
|
4 |
|
5 |
param sku object
|
6 |
param storage object
|
|
|
|
|
|
|
|
|
|
|
7 |
param administratorLogin string
|
8 |
@secure()
|
9 |
param administratorLoginPassword string
|
10 |
+
param databaseNames array = []
|
11 |
+
param allowAzureIPsFirewall bool = false
|
12 |
+
param allowAllIPsFirewall bool = false
|
13 |
+
param allowedSingleIPs array = []
|
14 |
|
15 |
// PostgreSQL version
|
|
|
16 |
param version string
|
17 |
|
18 |
+
// Latest official version 2022-12-01 does not have Bicep types available
|
19 |
+
resource postgresServer 'Microsoft.DBforPostgreSQL/flexibleServers@2022-12-01' = {
|
20 |
location: location
|
21 |
tags: tags
|
22 |
name: name
|
|
|
26 |
administratorLogin: administratorLogin
|
27 |
administratorLoginPassword: administratorLoginPassword
|
28 |
storage: storage
|
|
|
|
|
|
|
29 |
highAvailability: {
|
30 |
mode: 'Disabled'
|
31 |
}
|
32 |
}
|
33 |
|
34 |
+
resource database 'databases' = [for name in databaseNames: {
|
35 |
+
name: name
|
36 |
+
}]
|
37 |
+
|
38 |
+
resource firewall_all 'firewallRules' = if (allowAllIPsFirewall) {
|
39 |
+
name: 'allow-all-IPs'
|
40 |
+
properties: {
|
41 |
+
startIpAddress: '0.0.0.0'
|
42 |
+
endIpAddress: '255.255.255.255'
|
43 |
+
}
|
44 |
}
|
45 |
|
46 |
+
resource firewall_azure 'firewallRules' = if (allowAzureIPsFirewall) {
|
47 |
+
name: 'allow-all-azure-internal-IPs'
|
48 |
properties: {
|
49 |
startIpAddress: '0.0.0.0'
|
50 |
endIpAddress: '0.0.0.0'
|
51 |
}
|
52 |
}
|
53 |
|
54 |
+
resource firewall_single 'firewallRules' = [for ip in allowedSingleIPs: {
|
55 |
+
name: 'allow-single-${replace(ip, '.', '')}'
|
56 |
+
properties: {
|
57 |
+
startIpAddress: ip
|
58 |
+
endIpAddress: ip
|
59 |
+
}
|
60 |
+
}]
|
61 |
+
|
62 |
}
|
63 |
+
|
64 |
+
output POSTGRES_DOMAIN_NAME string = postgresServer.properties.fullyQualifiedDomainName
|
infra/core/host/appservice.bicep
CHANGED
@@ -33,10 +33,7 @@ param numberOfWorkers int = -1
|
|
33 |
param scmDoBuildDuringDeployment bool = false
|
34 |
param use32BitWorkerProcess bool = false
|
35 |
param ftpsState string = 'FtpsOnly'
|
36 |
-
|
37 |
-
// Microsoft.Web/sites/networkConfig
|
38 |
-
param subnetResourceId string = ''
|
39 |
-
param virtualNetwork object
|
40 |
|
41 |
resource appService 'Microsoft.Web/sites@2022-03-01' = {
|
42 |
name: name
|
@@ -49,11 +46,13 @@ resource appService 'Microsoft.Web/sites@2022-03-01' = {
|
|
49 |
linuxFxVersion: linuxFxVersion
|
50 |
alwaysOn: alwaysOn
|
51 |
ftpsState: ftpsState
|
|
|
52 |
appCommandLine: appCommandLine
|
53 |
numberOfWorkers: numberOfWorkers != -1 ? numberOfWorkers : null
|
54 |
minimumElasticInstanceCount: minimumElasticInstanceCount != -1 ? minimumElasticInstanceCount : null
|
55 |
use32BitWorkerProcess: use32BitWorkerProcess
|
56 |
functionAppScaleLimit: functionAppScaleLimit != -1 ? functionAppScaleLimit : null
|
|
|
57 |
cors: {
|
58 |
allowedOrigins: union([ 'https://portal.azure.com', 'https://ms.portal.azure.com' ], allowedOrigins)
|
59 |
}
|
@@ -87,15 +86,6 @@ resource appService 'Microsoft.Web/sites@2022-03-01' = {
|
|
87 |
configAppSettings
|
88 |
]
|
89 |
}
|
90 |
-
|
91 |
-
resource webappVnetConfig 'networkConfig' = if (!(empty(virtualNetwork))) {
|
92 |
-
name: 'virtualNetwork'
|
93 |
-
properties: {
|
94 |
-
subnetResourceId: subnetResourceId
|
95 |
-
}
|
96 |
-
}
|
97 |
-
|
98 |
-
dependsOn: empty(virtualNetwork) ? [] : [virtualNetwork]
|
99 |
}
|
100 |
|
101 |
resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = if (!(empty(keyVaultName))) {
|
|
|
33 |
param scmDoBuildDuringDeployment bool = false
|
34 |
param use32BitWorkerProcess bool = false
|
35 |
param ftpsState string = 'FtpsOnly'
|
36 |
+
param healthCheckPath string = ''
|
|
|
|
|
|
|
37 |
|
38 |
resource appService 'Microsoft.Web/sites@2022-03-01' = {
|
39 |
name: name
|
|
|
46 |
linuxFxVersion: linuxFxVersion
|
47 |
alwaysOn: alwaysOn
|
48 |
ftpsState: ftpsState
|
49 |
+
minTlsVersion: '1.2'
|
50 |
appCommandLine: appCommandLine
|
51 |
numberOfWorkers: numberOfWorkers != -1 ? numberOfWorkers : null
|
52 |
minimumElasticInstanceCount: minimumElasticInstanceCount != -1 ? minimumElasticInstanceCount : null
|
53 |
use32BitWorkerProcess: use32BitWorkerProcess
|
54 |
functionAppScaleLimit: functionAppScaleLimit != -1 ? functionAppScaleLimit : null
|
55 |
+
healthCheckPath: healthCheckPath
|
56 |
cors: {
|
57 |
allowedOrigins: union([ 'https://portal.azure.com', 'https://ms.portal.azure.com' ], allowedOrigins)
|
58 |
}
|
|
|
86 |
configAppSettings
|
87 |
]
|
88 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
}
|
90 |
|
91 |
resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = if (!(empty(keyVaultName))) {
|
infra/main.bicep
CHANGED
@@ -9,9 +9,20 @@ param name string
|
|
9 |
@description('Primary location for all resources')
|
10 |
param location string
|
11 |
|
|
|
|
|
|
|
|
|
12 |
@secure()
|
13 |
@description('PostGreSQL Server administrator password')
|
14 |
-
param
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
|
16 |
var resourceToken = toLower(uniqueString(subscription().id, name, location))
|
17 |
var tags = { 'azd-env-name': name }
|
@@ -26,19 +37,7 @@ var prefix = '${name}-${resourceToken}'
|
|
26 |
|
27 |
var postgresServerName = '${prefix}-postgresql'
|
28 |
|
29 |
-
|
30 |
-
name: 'virtualnetwork'
|
31 |
-
scope: resourceGroup
|
32 |
-
params: {
|
33 |
-
name: '${prefix}-vnet'
|
34 |
-
location: location
|
35 |
-
tags: tags
|
36 |
-
postgresServerName: postgresServerName
|
37 |
-
}
|
38 |
-
}
|
39 |
-
|
40 |
-
var databaseName = 'django'
|
41 |
-
var databaseUser = 'django'
|
42 |
|
43 |
module postgresServer 'core/database/postgresql/flexibleserver.bicep' = {
|
44 |
name: 'postgresql'
|
@@ -54,13 +53,11 @@ module postgresServer 'core/database/postgresql/flexibleserver.bicep' = {
|
|
54 |
storage: {
|
55 |
storageSizeGB: 32
|
56 |
}
|
57 |
-
version: '
|
58 |
-
administratorLogin:
|
59 |
-
administratorLoginPassword:
|
60 |
-
|
61 |
-
|
62 |
-
privateDnsZoneArmResourceId: virtualNetwork.outputs.privateDnsZoneId
|
63 |
-
privateDnsZoneLink: virtualNetwork.outputs.privateDnsZoneLink
|
64 |
}
|
65 |
}
|
66 |
|
@@ -78,13 +75,12 @@ module web 'core/host/appservice.bicep' = {
|
|
78 |
ftpsState: 'Disabled'
|
79 |
managedIdentity: true
|
80 |
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'
|
81 |
-
virtualNetwork: virtualNetwork
|
82 |
-
subnetResourceId: virtualNetwork.outputs.webSubnetId
|
83 |
appSettings: {
|
84 |
DBHOST: postgresServerName
|
85 |
-
DBNAME:
|
86 |
-
DBUSER:
|
87 |
-
DBPASS:
|
|
|
88 |
}
|
89 |
}
|
90 |
}
|
@@ -104,6 +100,45 @@ module appServicePlan 'core/host/appserviceplan.bicep' = {
|
|
104 |
}
|
105 |
}
|
106 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
module logAnalyticsWorkspace 'core/monitor/loganalytics.bicep' = {
|
108 |
name: 'loganalytics'
|
109 |
scope: resourceGroup
|
|
|
9 |
@description('Primary location for all resources')
|
10 |
param location string
|
11 |
|
12 |
+
@secure()
|
13 |
+
@description('PostGreSQL Server administrator username')
|
14 |
+
param postgresAdminUser string
|
15 |
+
|
16 |
@secure()
|
17 |
@description('PostGreSQL Server administrator password')
|
18 |
+
param postgresAdminPassword string
|
19 |
+
|
20 |
+
@description('Id of the user or app to assign application roles')
|
21 |
+
param principalId string = ''
|
22 |
+
|
23 |
+
@secure()
|
24 |
+
@description('Django SECRET_KEY for cryptographic signing')
|
25 |
+
param djangoSecretKey string
|
26 |
|
27 |
var resourceToken = toLower(uniqueString(subscription().id, name, location))
|
28 |
var tags = { 'azd-env-name': name }
|
|
|
37 |
|
38 |
var postgresServerName = '${prefix}-postgresql'
|
39 |
|
40 |
+
var postgresDatabaseName = 'django'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
|
42 |
module postgresServer 'core/database/postgresql/flexibleserver.bicep' = {
|
43 |
name: 'postgresql'
|
|
|
53 |
storage: {
|
54 |
storageSizeGB: 32
|
55 |
}
|
56 |
+
version: '14'
|
57 |
+
administratorLogin: postgresAdminUser
|
58 |
+
administratorLoginPassword: postgresAdminPassword
|
59 |
+
databaseNames: [postgresDatabaseName]
|
60 |
+
allowAzureIPsFirewall: true
|
|
|
|
|
61 |
}
|
62 |
}
|
63 |
|
|
|
75 |
ftpsState: 'Disabled'
|
76 |
managedIdentity: true
|
77 |
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'
|
|
|
|
|
78 |
appSettings: {
|
79 |
DBHOST: postgresServerName
|
80 |
+
DBNAME: postgresDatabaseName
|
81 |
+
DBUSER: '@Microsoft.KeyVault(VaultName=${keyVault.outputs.name};SecretName=postgresAdminUser)'
|
82 |
+
DBPASS: '@Microsoft.KeyVault(VaultName=${keyVault.outputs.name};SecretName=postgresAdminPassword)'
|
83 |
+
SECRET_KEY: '@Microsoft.KeyVault(VaultName=${keyVault.outputs.name};SecretName=djangoSecretKey)'
|
84 |
}
|
85 |
}
|
86 |
}
|
|
|
100 |
}
|
101 |
}
|
102 |
|
103 |
+
// Store secrets in a keyvault
|
104 |
+
module keyVault './core/security/keyvault.bicep' = {
|
105 |
+
name: 'keyvault'
|
106 |
+
scope: resourceGroup
|
107 |
+
params: {
|
108 |
+
name: '${take(replace(prefix, '-', ''), 17)}-vault'
|
109 |
+
location: location
|
110 |
+
tags: tags
|
111 |
+
principalId: principalId
|
112 |
+
}
|
113 |
+
}
|
114 |
+
|
115 |
+
var secrets = [
|
116 |
+
{
|
117 |
+
name: 'djangoSecretKey'
|
118 |
+
value: djangoSecretKey
|
119 |
+
}
|
120 |
+
{
|
121 |
+
name: 'postgresAdminUser'
|
122 |
+
value: postgresAdminUser
|
123 |
+
}
|
124 |
+
{
|
125 |
+
name: 'postgresAdminPassword'
|
126 |
+
value: postgresAdminPassword
|
127 |
+
}
|
128 |
+
]
|
129 |
+
|
130 |
+
@batchSize(1)
|
131 |
+
module keyVaultSecrets './core/security/keyvault-secret.bicep' = [for secret in secrets: {
|
132 |
+
name: 'keyvault-secret-${secret.name}'
|
133 |
+
scope: resourceGroup
|
134 |
+
params: {
|
135 |
+
keyVaultName: keyVault.outputs.name
|
136 |
+
name: secret.name
|
137 |
+
secretValue: secret.value
|
138 |
+
}
|
139 |
+
}]
|
140 |
+
|
141 |
+
|
142 |
module logAnalyticsWorkspace 'core/monitor/loganalytics.bicep' = {
|
143 |
name: 'loganalytics'
|
144 |
scope: resourceGroup
|
infra/main.parameters.json
CHANGED
@@ -8,8 +8,17 @@
|
|
8 |
"location": {
|
9 |
"value": "${AZURE_LOCATION}"
|
10 |
},
|
11 |
-
"
|
12 |
-
"value": "$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
}
|
14 |
}
|
15 |
}
|
|
|
8 |
"location": {
|
9 |
"value": "${AZURE_LOCATION}"
|
10 |
},
|
11 |
+
"principalId": {
|
12 |
+
"value": "${AZURE_PRINCIPAL_ID}"
|
13 |
+
},
|
14 |
+
"postgresAdminUser": {
|
15 |
+
"value": "$(secretOrRandomPassword ${AZURE_KEY_VAULT_NAME} postgresAdminUser)"
|
16 |
+
},
|
17 |
+
"postgresAdminPassword": {
|
18 |
+
"value": "$(secretOrRandomPassword ${AZURE_KEY_VAULT_NAME} postgresAdminPassword)"
|
19 |
+
},
|
20 |
+
"djangoSecretKey": {
|
21 |
+
"value": "$(secretOrRandomPassword ${AZURE_KEY_VAULT_NAME} djangoSecretKey)"
|
22 |
}
|
23 |
}
|
24 |
}
|
pyproject.toml
CHANGED
@@ -1,14 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
1 |
[tool.black]
|
|
|
2 |
line-length = 120
|
3 |
-
target-version = ['py39']
|
4 |
exclude = '''
|
5 |
/(
|
6 |
| \.venv
|
7 |
| migrations
|
8 |
)/
|
9 |
-
|
10 |
'''
|
11 |
-
|
12 |
-
[tool.ruff]
|
13 |
-
line-length = 120
|
14 |
-
ignore = ['D203']
|
|
|
1 |
+
[tool.ruff]
|
2 |
+
select = ["E", "F", "I", "UP"]
|
3 |
+
target-version = "py310"
|
4 |
+
line-length = 120
|
5 |
+
|
6 |
[tool.black]
|
7 |
+
target-version = ['py310']
|
8 |
line-length = 120
|
|
|
9 |
exclude = '''
|
10 |
/(
|
11 |
| \.venv
|
12 |
| migrations
|
13 |
)/
|
|
|
14 |
'''
|
|
|
|
|
|
|
|