Skip to content

Commit 56218b2

Browse files
committed
Add azure wrapper to postgresql implementation
1 parent 6843720 commit 56218b2

File tree

3 files changed

+41
-1
lines changed

3 files changed

+41
-1
lines changed

lung_cancer_screening/config/postgresql/__init__.py

Whitespace-only changes.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from azure.identity import DefaultAzureCredential
2+
from django.db.backends.postgresql import base
3+
4+
5+
class DatabaseWrapper(base.DatabaseWrapper):
6+
"""
7+
Wrap the Postgres engine to support Azure passwordless login
8+
https://learn.microsoft.com/en-us/azure/developer/intro/passwordless-overview
9+
10+
This involves fetching a token at runtime to use as the database password.
11+
12+
The consequence of this is our database credentials aren't static - they
13+
expire. We therefore need to ensure that every new connection
14+
checks the expiry date, and fetches a new one if necessary.
15+
16+
Unless you disable persistent connections, each thread will maintain its own
17+
connection.
18+
Since Django 5.1 it is possible to configure a connection pool
19+
instead of using persistent connections, but that would require us to
20+
fix the credentials.
21+
See https://docs.djangoproject.com/en/5.2/ref/databases/#persistent-connections
22+
for more details of how this works.
23+
"""
24+
25+
def __init__(self, *args, **kwargs):
26+
super().__init__(*args, **kwargs)
27+
self.azure_credential = DefaultAzureCredential()
28+
29+
def _get_azure_connection_password(self) -> str:
30+
# This makes use of in-memory token caching
31+
# https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/identity/azure-identity/TOKEN_CACHING.md#in-memory-token-caching
32+
return self.azure_credential.get_token(
33+
"https://ossrdbms-aad.database.windows.net/.default"
34+
).token
35+
36+
def get_connection_params(self) -> dict:
37+
params = super().get_connection_params()
38+
if params.get("host", "").endswith(".database.azure.com"):
39+
params["password"] = self._get_azure_connection_password()
40+
return params

lung_cancer_screening/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ def boolean_env(key, default=None):
9595

9696
DATABASES = {
9797
"default": {
98-
"ENGINE": "django.db.backends.postgresql",
98+
"ENGINE": "lung_cancer_screening.config.postgresql",
9999
"NAME": environ.get("DATABASE_NAME", ""),
100100
"USER": environ.get("DATABASE_USER", ""),
101101
"PASSWORD": environ.get("DATABASE_PASSWORD", ""),

0 commit comments

Comments
 (0)