Skip to content

Commit 372f5f5

Browse files
committed
Add pgaudit audit logging with 90-day diagnostic storage retention for compliance
1 parent 8a41e70 commit 372f5f5

4 files changed

Lines changed: 87 additions & 3 deletions

File tree

cloud-infrastructure/cluster/grant-database-permissions.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,12 @@ END
3535
\$\$;
3636
EOF
3737

38-
PGPASSWORD=$ACCESS_TOKEN psql -v ON_ERROR_STOP=1 "host=$POSTGRES_HOST dbname=$DATABASE_NAME user='$ENTRA_USER' sslmode=verify-full sslrootcert=system" << EOF
38+
PGPASSWORD=$ACCESS_TOKEN psql "host=$POSTGRES_HOST dbname=$DATABASE_NAME user='$ENTRA_USER' sslmode=verify-full sslrootcert=system" << EOF
3939
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
40+
CREATE EXTENSION IF NOT EXISTS pgaudit;
41+
EOF
42+
43+
PGPASSWORD=$ACCESS_TOKEN psql -v ON_ERROR_STOP=1 "host=$POSTGRES_HOST dbname=$DATABASE_NAME user='$ENTRA_USER' sslmode=verify-full sslrootcert=system" << EOF
4044
GRANT CONNECT ON DATABASE "$DATABASE_NAME" TO "$MANAGED_IDENTITY_NAME";
4145
GRANT USAGE ON SCHEMA public TO "$MANAGED_IDENTITY_NAME";
4246
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO "$MANAGED_IDENTITY_NAME";

cloud-infrastructure/cluster/main-cluster.bicep

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ module diagnosticStorageAccount '../modules/storage-account.bicep' = {
5757
}
5858
}
5959

60+
module diagnosticStorageRetention '../modules/storage-account-retention.bicep' = {
61+
scope: clusterResourceGroup
62+
name: '${clusterResourceGroupName}-diagnostic-storage-retention'
63+
params: {
64+
storageAccountName: diagnosticStorageAccount.outputs.name
65+
retentionDays: 90
66+
}
67+
}
68+
6069
module virtualNetwork '../modules/virtual-network.bicep' = {
6170
scope: clusterResourceGroup
6271
name: '${clusterResourceGroupName}-virtual-network'
@@ -143,6 +152,7 @@ module postgresServer '../modules/postgresql-flexible-server.bicep' = {
143152
subnetId: virtualNetwork.outputs.privateEndpointSubnetId
144153
virtualNetworkId: virtualNetwork.outputs.virtualNetworkId
145154
isProduction: environment == 'prod'
155+
diagnosticStorageAccountId: diagnosticStorageAccount.outputs.storageAccountId
146156
}
147157
}
148158

cloud-infrastructure/modules/postgresql-flexible-server.bicep

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ param tenantId string
55
param subnetId string
66
param virtualNetworkId string
77
param isProduction bool
8+
param diagnosticStorageAccountId string
89

910
resource postgresServer 'Microsoft.DBforPostgreSQL/flexibleServers@2025-08-01' = {
1011
name: name
@@ -103,20 +104,55 @@ resource extensionsConfig 'Microsoft.DBforPostgreSQL/flexibleServers/configurati
103104
name: 'azure.extensions'
104105
dependsOn: [privateDnsZoneGroup]
105106
properties: {
106-
value: 'pg_stat_statements'
107+
value: 'pg_stat_statements,pgaudit'
108+
source: 'user-override'
109+
}
110+
}
111+
112+
resource sharedPreloadLibrariesConfig 'Microsoft.DBforPostgreSQL/flexibleServers/configurations@2025-08-01' = {
113+
parent: postgresServer
114+
name: 'shared_preload_libraries'
115+
dependsOn: [extensionsConfig]
116+
properties: {
117+
value: 'pgaudit'
118+
source: 'user-override'
119+
}
120+
}
121+
122+
resource pgauditLogConfig 'Microsoft.DBforPostgreSQL/flexibleServers/configurations@2025-08-01' = {
123+
parent: postgresServer
124+
name: 'pgaudit.log'
125+
dependsOn: [sharedPreloadLibrariesConfig]
126+
properties: {
127+
value: 'WRITE,DDL,ROLE'
107128
source: 'user-override'
108129
}
109130
}
110131

111132
resource walLevelConfig 'Microsoft.DBforPostgreSQL/flexibleServers/configurations@2025-08-01' = {
112133
parent: postgresServer
113134
name: 'wal_level'
114-
dependsOn: [extensionsConfig]
135+
dependsOn: [pgauditLogConfig]
115136
properties: {
116137
value: 'logical'
117138
source: 'user-override'
118139
}
119140
}
120141

142+
resource diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = {
143+
name: '${name}-postgres-diagnostics'
144+
scope: postgresServer
145+
dependsOn: [walLevelConfig]
146+
properties: {
147+
storageAccountId: diagnosticStorageAccountId
148+
logs: [
149+
{
150+
categoryGroup: 'allLogs'
151+
enabled: true
152+
}
153+
]
154+
}
155+
}
156+
121157
output serverName string = postgresServer.name
122158
output serverFqdn string = postgresServer.properties.fullyQualifiedDomainName
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
param storageAccountName string
2+
param retentionDays int
3+
4+
resource storageAccount 'Microsoft.Storage/storageAccounts@2025-06-01' existing = {
5+
name: storageAccountName
6+
}
7+
8+
resource lifecyclePolicy 'Microsoft.Storage/storageAccounts/managementPolicies@2025-06-01' = {
9+
parent: storageAccount
10+
name: 'default'
11+
properties: {
12+
policy: {
13+
rules: [
14+
{
15+
name: 'delete-after-${retentionDays}-days'
16+
enabled: true
17+
type: 'Lifecycle'
18+
definition: {
19+
actions: {
20+
baseBlob: {
21+
delete: {
22+
daysAfterModificationGreaterThan: retentionDays
23+
}
24+
}
25+
}
26+
filters: {
27+
blobTypes: ['blockBlob', 'appendBlob']
28+
}
29+
}
30+
}
31+
]
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)