Microsoft Defender for Cloud · Azure Database for PostgreSQL flexible server
pgaudit.log_statement should be set to "on" for Azure Database for PostgreSQL Servers
Written and reviewed by Emnode · Last reviewed
What does the recommendation "pgaudit.log_statement should be set to "on" for Azure Database for PostgreSQL Servers" check?
Flags any Azure Database for PostgreSQL flexible server where the 'pgaudit.log_statement' server parameter is not set to 'on'. With this on, the pgaudit extension records the literal SQL text of every audited statement in the audit trail rather than just its statement class, so a reviewer can see exactly what ran. It checks only this one parameter: it does not verify that pgaudit is listed in 'shared_preload_libraries', that 'azure.extensions' allows pgaudit, that 'pgaudit.log' selects the right statement classes, or that the server's logs are actually shipped to a workspace or storage. It also does not apply to the retired Single Server tier.
Why does "pgaudit.log_statement should be set to "on" for Azure Database for PostgreSQL Servers" matter?
Audit logging without statement text is a half-measure. If pgaudit logs only that a WRITE or DDL class fired but not the statement itself, an investigation after a data tampering or exfiltration incident cannot tell which rows changed, which table was dropped, or what a compromised account actually did. That gap turns a forensic timeline into guesswork and can leave you unable to prove scope to an auditor or regulator. Setting 'pgaudit.log_statement' to 'on' captures the full statement, giving security and compliance teams the evidence they need to reconstruct activity and meet logging obligations under frameworks such as PCI DSS and ISO 27001.
How do I fix "pgaudit.log_statement should be set to "on" for Azure Database for PostgreSQL Servers"?
- Confirm pgaudit is loadable first: ensure 'pgaudit' is present in both the 'azure.extensions' allowlist and 'shared_preload_libraries' server parameters, then restart the server if you changed 'shared_preload_libraries', because the extension cannot capture statements until it is preloaded.
- Set the parameter with: az postgres flexible-server parameter set --resource-group <rg> --server-name <server> --source user-override --name pgaudit.log_statement --value on. In the portal the same change is under Settings, Server parameters, by searching for 'pgaudit.log_statement' and selecting 'on'. In Bicep, add a child 'configurations' resource named 'pgaudit.log_statement' with value 'on' and source 'user-override'.
- Enforce it at scale by assigning the built-in policy by its exact display name rather than a hardcoded GUID: pid=$(az policy definition list --query "[?displayName=='Auditing with PgAudit should be enabled for PostgreSQL flexible servers'].name" -o tsv); az policy assignment create --name pg-pgaudit-on --policy "$pid" --scope <scope>. Pair it with a diagnostic setting that routes PostgreSQL logs to a Log Analytics workspace so the captured statements are retained off the server.
Remediation script · bash
# 1. Lock the wire and the network on a production PostgreSQL flexible server.
RG=db-prod-rg
SRV=ordersprod-pg
# Enforce encrypted connections (dynamic, no restart needed).
az postgres flexible-server parameter set \
--resource-group "$RG" --server-name "$SRV" \
--source user-override \
--name require_secure_transport --value ON
# Pin the minimum TLS version.
az postgres flexible-server parameter set \
--resource-group "$RG" --server-name "$SRV" \
--source user-override \
--name ssl_min_protocol_version --value TLSv1.2
# Disable public network access.
az postgres flexible-server update \
--resource-group "$RG" --name "$SRV" \
--public-access Disabled
# 2. Turn on the pgaudit trail and connection throttling.
for p in "pgaudit.log=role,ddl,misc" \
"pgaudit.log_client=ON" \
"pgaudit.log_level=log" \
"pgaudit.log_statement=on" \
"pgaudit.log_statement_once=on" \
"connection_throttle.enable=on"; do
az postgres flexible-server parameter set \
--resource-group "$RG" --server-name "$SRV" \
--source user-override \
--name "${p%%=*}" --value "${p#*=}"
done
# 3. Provision a Microsoft Entra administrator and disable password sign-in.
az postgres flexible-server ad-admin create \
--resource-group "$RG" --server-name "$SRV" \
--display-name "dba-team" \
--object-id "$(az ad group show --group dba-team --query id -o tsv)" \
--type Group
az postgres flexible-server update \
--resource-group "$RG" --name "$SRV" \
--microsoft-entra-auth Enabled --password-auth Disabled
# 4. Ratchet it shut: deny any future PostgreSQL flexible server with public access.
# Look the built-in policy up by its EXACT display name, never paste a guessed GUID.
PID=$(az policy definition list \
--query "[?displayName=='Public network access should be disabled for PostgreSQL flexible servers'].name" \
-o tsv)
az policy assignment create \
--name deny-public-pg-flex \
--policy "$PID" \
--params '{"effect":{"value":"Deny"}}' \
--scope "/subscriptions/00000000-0000-0000-0000-000000000000" Full walkthrough (console steps, edge cases and verification) in the lesson Harden Azure MySQL and PostgreSQL.
Is "pgaudit.log_statement should be set to "on" for Azure Database for PostgreSQL Servers" a false positive?
A read-only reporting replica or a server holding only synthetic, non-sensitive test data may deliberately leave 'pgaudit.log_statement' off to avoid the write amplification and log volume of recording full statement text. That is a defensible exception where no regulated or production data is present. Document the decision, scope the policy assignment to exclude that server, and revisit it if the workload ever starts handling real customer data.
More Azure Database for PostgreSQL flexible server controls
- 'Allow access to Azure services' should be disabled for PostgreSQL Servers
- Azure Database for PostgreSQL flexible server should have Microsoft Entra authentication only enabled
- connection_throttle should be set to "on" for PostgreSQL Servers
- logfiles.retention_days should be greater than 3 for PostgreSQL Servers
- pgaudit.log should include role, ddl, and misc for Azure Database for PostgreSQL Servers
- pgaudit.log_level should be set to "log" for Azure Database for PostgreSQL Servers
- pgaudit.log_statement_once should be set to "on" for Azure Database for PostgreSQL Servers
- Private endpoint should be configured for Azure Database for PostgreSQL Servers
- Public IP access should be disabled for Azure Database for PostgreSQL Servers
- require_secure_transport should be set to "on" for Azure Database for PostgreSQL servers