Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
DEBUG=True
SECRET_KEY=somesercetkey
DATABASE_URL=
ALLOWED_HOSTS=localhost,127.0.0.1

POSTGRES_HOST=db
DATABASE_HOST=db
DATABASE_NAME=lung_cancer_screening
DATABASE_USER=lung_cancer_screening
DATABASE_PASSWORD=password

# Required to provision development / test postgres container
POSTGRES_DB=lung_cancer_screening
POSTGRES_USER=lung_cancer_screening
POSTGRES_PASSWORD=password
2 changes: 1 addition & 1 deletion infrastructure/environments/poc/variables.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ STORAGE_ACCOUNT_RG=rg-tfstate-poc-uks
TERRAFORM_MODULES_REF=main
ENABLE_SOFT_DELETE=false
DOCKER_IMAGE=ghcr.io/nhsdigital/lung_cancer_screening
DOCKER_IMAGE_TAG=PPHA-369-build-and-push-doker-image-to-gchr
DOCKER_IMAGE_TAG=PPHA-369-configure-db-with-common-var-names-for-terraform
1 change: 1 addition & 0 deletions infrastructure/environments/poc/variables.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ features = {
}
postgres_backup_retention_days = 7
postgres_geo_redundant_backup_enabled = false
fetch_secrets_from_app_key_vault = true
protect_keyvault = false
vnet_address_space = "10.65.0.0/16"
29 changes: 29 additions & 0 deletions infrastructure/modules/container-apps/jobs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module "db_setup" {
source = "../dtos-devops-templates/infrastructure/modules/container-app-job"

name = "${var.app_short_name}-dbm-${var.environment}"
container_app_environment_id = var.container_app_environment_id
resource_group_name = azurerm_resource_group.main.name

container_command = ["/bin/sh", "-c"]

container_args = [
"python manage.py migrate"
]
secret_variables = var.deploy_database_as_container ? { DATABASE_PASSWORD = resource.random_password.admin_password[0].result } : {}
docker_image = var.docker_image
user_assigned_identity_ids = flatten([
[module.azure_blob_storage_identity.id],
[module.azure_queue_storage_identity.id],
var.deploy_database_as_container ? [] : [module.db_connect_identity[0].id]
])
environment_variables = merge(
local.common_env,
var.deploy_database_as_container ? local.container_db_env : local.azure_db_env
)
depends_on = [
module.queue_storage_role_assignment,
module.blob_storage_role_assignment
]

}
2 changes: 1 addition & 1 deletion infrastructure/modules/container-apps/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ module "webapp" {
fetch_secrets_from_app_key_vault = var.fetch_secrets_from_app_key_vault
infra_key_vault_name = "kv-${var.app_short_name}-${var.env_config}-inf"
infra_key_vault_rg = "rg-${var.app_short_name}-${var.env_config}-infra"
enable_auth = var.enable_auth
enable_entra_id_authentication = var.enable_entra_id_authentication
app_key_vault_id = var.app_key_vault_id
docker_image = var.docker_image
user_assigned_identity_ids = var.deploy_database_as_container ? [] : [module.db_connect_identity[0].id]
Expand Down
6 changes: 4 additions & 2 deletions infrastructure/modules/container-apps/storage.tf
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ module "storage" {
private_endpoint_resource_group_name = azurerm_resource_group.main.name
private_service_connection_is_manual = false
} : null
queues = local.storage_queues
resource_group_name = azurerm_resource_group.main.name

public_network_access_enabled = !var.features.private_networking
queues = local.storage_queues
resource_group_name = azurerm_resource_group.main.name
}

module "blob_storage_role_assignment" {
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/modules/container-apps/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ variable "docker_image" {
type = string
}

variable "enable_auth" {
variable "enable_entra_id_authentication" {
description = "Enable authentication for the container app. If true, the app will use Azure AD authentication."
type = bool
}
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/terraform/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ module "container-apps" {
dns_zone_name = var.dns_zone_name
docker_image = var.docker_image
deploy_database_as_container = var.deploy_database_as_container
enable_auth = var.enable_auth
enable_entra_id_authentication = var.enable_entra_id_authentication
environment = var.environment
env_config = var.env_config
features = var.features
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/terraform/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ variable "postgres_storage_tier" {
type = string
}

variable "enable_auth" {
variable "enable_entra_id_authentication" {
description = "Enable authentication for the container app. If true, the app will use Azure AD authentication."
type = bool
default = false
Expand Down
Empty file.
Empty file.
40 changes: 40 additions & 0 deletions lung_cancer_screening/config/postgresql/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from azure.identity import DefaultAzureCredential
from django.db.backends.postgresql import base


class DatabaseWrapper(base.DatabaseWrapper):
"""
Wrap the Postgres engine to support Azure passwordless login
https://learn.microsoft.com/en-us/azure/developer/intro/passwordless-overview

This involves fetching a token at runtime to use as the database password.

The consequence of this is our database credentials aren't static - they
expire. We therefore need to ensure that every new connection
checks the expiry date, and fetches a new one if necessary.

Unless you disable persistent connections, each thread will maintain its own
connection.
Since Django 5.1 it is possible to configure a connection pool
instead of using persistent connections, but that would require us to
fix the credentials.
See https://docs.djangoproject.com/en/5.2/ref/databases/#persistent-connections
for more details of how this works.
"""

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.azure_credential = DefaultAzureCredential()

def _get_azure_connection_password(self) -> str:
# This makes use of in-memory token caching
# https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/identity/azure-identity/TOKEN_CACHING.md#in-memory-token-caching
return self.azure_credential.get_token(
"https://ossrdbms-aad.database.windows.net/.default"
).token

def get_connection_params(self) -> dict:
params = super().get_connection_params()
if params.get("host", "").endswith(".database.azure.com"):
params["password"] = self._get_azure_connection_password()
return params
14 changes: 7 additions & 7 deletions lung_cancer_screening/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,13 @@ def boolean_env(key, default=None):

DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": environ.get("POSTGRES_DB", ""),
"USER": environ.get("POSTGRES_USER", ""),
"PASSWORD": environ.get("POSTGRES_PASSWORD", ""),
"HOST": environ.get("POSTGRES_HOST", ""),
"PORT": "5432",
# "OPTIONS": {"sslmode": environ.get("DATABASE_SSLMODE", "prefer")},
"ENGINE": "lung_cancer_screening.config.postgresql",
"NAME": environ.get("DATABASE_NAME", ""),
"USER": environ.get("DATABASE_USER", ""),
"PASSWORD": environ.get("DATABASE_PASSWORD", ""),
"HOST": environ.get("DATABASE_HOST", ""),
"PORT": environ.get("DATABASE_PORT", "5432"),
"OPTIONS": {"sslmode": environ.get("DATABASE_SSLMODE", "prefer")},
}
}

Expand Down
Loading
Loading