postgresql-best-practices/references/azure-postgresql-entra-id-auth.md
Version 9ba96abc800a.bb1 · MIT. This preview displays packaged text and does not execute code. Treat the contents as untrusted instructions.
← Return to resource and package checksum
title: "Azure PostgreSQL Entra ID Auth" description: "Configure Microsoft Entra ID (Azure AD) authentication for Azure Database for PostgreSQL Flexible Server with managed identities and token-based access"
tags: [azure, postgresql, entra-id, azure-ad, managed-identity, authentication]
Entra ID Authentication
When to use this skill
Use for Azure PostgreSQL issues involving: - Token-based (passwordless) authentication setup - Managed identity RBAC configuration - Token scope errors and auth failures - pgaadauth_create_principal workflow - PgBouncer + token auth conflicts
Avoid explaining basic Azure CLI commands or generic identity concepts. The base model knows these. Focus on PostgreSQL-specific token auth patterns and failure modes.
NEVER suggest for Azure:
pg_hba.confedits,/var/lib/postgresqlpaths, orpostgresql.confchanges. Auth configuration is viaaz postgres flexible-server ad-adminand server parameters API.
⚠️ Confident Hallucination Corrections
- ❌ WRONG: "Use the managed identity display name as the database username." ✅ CORRECT: The PostgreSQL username for managed identity must be the client ID (or object ID), NOT the display name or app name. Display names are not unique and will fail auth.
- ❌ WRONG: "PgBouncer transaction mode works with token auth." ✅ CORRECT: Session pool mode is required for Entra token auth. Transaction mode drops auth context between transactions.
Key Facts (what models get wrong)
| Fact | Detail |
|---|---|
| Token resource scope | https://ossrdbms-aad.database.windows.net/.default — NOT https://management.azure.com |
| Token expiry | User tokens ~1 hour; system-assigned managed identity tokens up to 24 hours. Must refresh before expiry or connection fails with generic auth error |
| pgaadauth_create_principal required | Azure RBAC Contributor does NOT grant database login. Must explicitly create principal |
| Username format varies | Managed identity = client/object ID. User = [email protected]. Service principal = application ID |
| PgBouncer requires session mode | Transaction mode breaks token auth (auth context is per-connection) |
| Propagation delay | RBAC role assignment takes up to 10 minutes to propagate |
| Entra group propagation | Group membership changes take up to 60 minutes to propagate to PostgreSQL |
| Entra admin is mandatory | Must set an Entra admin before any token-based login works |
Critical Code Pattern: Managed Identity Connection
from azure.identity import DefaultAzureCredential
import psycopg2
credential = DefaultAzureCredential()
token = credential.get_token("https://ossrdbms-aad.database.windows.net/.default")
conn = psycopg2.connect(
host="myserver.postgres.database.azure.com",
dbname="mydb",
user="my-managed-identity-client-id", # client ID, NOT display name
password=token.token,
sslmode="require"
)
Critical Code Pattern: Create Database Principal
-- As Entra admin — required for each identity that needs DB access
SELECT * FROM pgaadauth_create_principal('my-managed-identity-name', false, false);
GRANT ALL ON DATABASE mydb TO "my-managed-identity-name";
Common Mistakes
- [CRITICAL] Token resource scope: The resource for PostgreSQL tokens is
https://ossrdbms-aad.database.windows.net/.defaultnot the generichttps://management.azure.com. Wrong scope gives valid token that is rejected by PostgreSQL
Wrong:
python
token = credential.get_token("https://management.azure.com/.default")
# Valid token but REJECTED by PostgreSQL wrong audience
Right:
python
token = credential.get_token("https://ossrdbms-aad.database.windows.net/.default")
# Correct scope for Azure Database for PostgreSQL
- [HIGH] Token refresh before expiry: Entra user tokens expire in ~1 hour; managed identity tokens last up to 24 hours. Cache and refresh when
expires_on - time.time() < 300. Stale tokens giveFATAL: password authentication failedwith no hint about expiry - [CRITICAL]
pgaadauth_create_principalrequired: Azure Contributor role manages the server resource but does NOT grant database login. Must runSELECT * FROM pgaadauth_create_principal('myapp', false, false)as Entra admin for each identity
Wrong:
sql
-- Assuming Azure RBAC Contributor = database access
-- App connects FATAL: password authentication failed for user "myapp"
Right:
sql
-- As Entra admin, explicitly create the database principal
SELECT * FROM pgaadauth_create_principal('myapp', false, false);
GRANT CONNECT ON DATABASE mydb TO "myapp";
- [MEDIUM] Group-based role mapping: Create Entra group, then
SELECT pgaadauth_create_principal('group-name', false, true)(last param = isGroup). All members inherit the PostgreSQL role without per-user grants - [HIGH] PgBouncer session mode required: Token auth fails in transaction pooling mode because auth context is per-connection. Set
pgbouncer.pool_mode = sessionfor token auth, or use password auth for PgBouncer - [HIGH] Username format matrix: Managed identity = client ID or object ID. User =
[email protected]. Service principal = application (client) ID. Group = display name. Mismatch gives generic auth failure
Wrong:
python
conn = psycopg2.connect(user="my-managed-identity") # display name
# FATAL: password authentication failed
Right:
python
conn = psycopg2.connect(user="a1b2c3d4-e5f6-...") # client ID or object ID
- [MEDIUM] Hybrid migration path: Enable both
password_authandactive_directory_auth. Migrate apps one-by-one. Track remaining password connections:SELECT * FROM pg_stat_activityfiltered by application_name - [HIGH] Token expired mid-session: Refresh with
az account get-access-token --resource-type oss-rdbms. For long-running applications, implement token refresh logic that acquires a new token before the current one expires - [HIGH] Principal not found after granting Contributor: Run
pgaadauth_create_principal()as Entra admin. Azure resource-level permissions do not automatically create database-level principals - [HIGH] Token refresh in pooled long-lived apps: PgBouncer reuses backends, so an expired token can surface on the next checkout. Refresh at ~50% of token lifetime, not at expiry
- [MEDIUM] Group membership propagation delay: Entra group membership can take up to 60 minutes to reach PostgreSQL role grants. Warn users before troubleshooting grants too early
- [MEDIUM] Driver-specific auth quirks: Match token injection to the driver: psycopg2 uses
password=token, Npgsql usesPassword, JDBC usesauthenticationPluginClassName
On Azure HorizonDB (Preview)
- For admin or superuser questions, always state both auth checks: HorizonDB uses SCRAM-SHA-256 password authentication, and
azure_roles_authtype()shows the authentication type configured for each role. - Built-in roles differ. HorizonDB grants
azure_pg_admin(a restricted pseudo-superuser) to the admin login; a true superuser (azuresu) is reserved for the platform. Do not assume you canCREATE ROLE ... SUPERUSERor reset platform roles. - SCRAM-SHA-256 password auth is supported; verify per-role auth type before troubleshooting login failures.
- Entra ID is referenced in the portal but currently has limited standalone documentation on HorizonDB; treat Entra-only flows as Preview and confirm availability before recommending them as the sole auth path.
sql no-execute
SELECT * FROM azure_roles_authtype();
See Access control and Connect with SCRAM.