Configure Azure SQL Database Blob Auditing Policies

The azure-native:sql:ExtendedDatabaseBlobAuditingPolicy resource, part of the Pulumi Azure Native provider, defines audit logging configuration for an Azure SQL database: its destination (Azure Monitor or blob storage), action groups, and retention settings. This guide focuses on three capabilities: Azure Monitor integration, blob storage archival, and selective auditing with action groups and predicates.

Audit policies reference existing SQL servers, databases, and storage accounts. When using Azure Monitor as a destination, you must configure Diagnostic Settings separately. The examples are intentionally small. Combine them with your own SQL infrastructure and monitoring setup.

Send audit events to Azure Monitor

Compliance teams often route SQL audit events to Azure Monitor for centralized log analysis and alerting, integrating with existing monitoring infrastructure.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const extendedDatabaseBlobAuditingPolicy = new azure_native.sql.ExtendedDatabaseBlobAuditingPolicy("extendedDatabaseBlobAuditingPolicy", {
    blobAuditingPolicyName: "default",
    databaseName: "testdb",
    isAzureMonitorTargetEnabled: true,
    resourceGroupName: "blobauditingtest-4799",
    serverName: "blobauditingtest-6440",
    state: azure_native.sql.BlobAuditingPolicyState.Enabled,
});
import pulumi
import pulumi_azure_native as azure_native

extended_database_blob_auditing_policy = azure_native.sql.ExtendedDatabaseBlobAuditingPolicy("extendedDatabaseBlobAuditingPolicy",
    blob_auditing_policy_name="default",
    database_name="testdb",
    is_azure_monitor_target_enabled=True,
    resource_group_name="blobauditingtest-4799",
    server_name="blobauditingtest-6440",
    state=azure_native.sql.BlobAuditingPolicyState.ENABLED)
package main

import (
	sql "github.com/pulumi/pulumi-azure-native-sdk/sql/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := sql.NewExtendedDatabaseBlobAuditingPolicy(ctx, "extendedDatabaseBlobAuditingPolicy", &sql.ExtendedDatabaseBlobAuditingPolicyArgs{
			BlobAuditingPolicyName:      pulumi.String("default"),
			DatabaseName:                pulumi.String("testdb"),
			IsAzureMonitorTargetEnabled: pulumi.Bool(true),
			ResourceGroupName:           pulumi.String("blobauditingtest-4799"),
			ServerName:                  pulumi.String("blobauditingtest-6440"),
			State:                       sql.BlobAuditingPolicyStateEnabled,
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var extendedDatabaseBlobAuditingPolicy = new AzureNative.Sql.ExtendedDatabaseBlobAuditingPolicy("extendedDatabaseBlobAuditingPolicy", new()
    {
        BlobAuditingPolicyName = "default",
        DatabaseName = "testdb",
        IsAzureMonitorTargetEnabled = true,
        ResourceGroupName = "blobauditingtest-4799",
        ServerName = "blobauditingtest-6440",
        State = AzureNative.Sql.BlobAuditingPolicyState.Enabled,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.sql.ExtendedDatabaseBlobAuditingPolicy;
import com.pulumi.azurenative.sql.ExtendedDatabaseBlobAuditingPolicyArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var extendedDatabaseBlobAuditingPolicy = new ExtendedDatabaseBlobAuditingPolicy("extendedDatabaseBlobAuditingPolicy", ExtendedDatabaseBlobAuditingPolicyArgs.builder()
            .blobAuditingPolicyName("default")
            .databaseName("testdb")
            .isAzureMonitorTargetEnabled(true)
            .resourceGroupName("blobauditingtest-4799")
            .serverName("blobauditingtest-6440")
            .state("Enabled")
            .build());

    }
}
resources:
  extendedDatabaseBlobAuditingPolicy:
    type: azure-native:sql:ExtendedDatabaseBlobAuditingPolicy
    properties:
      blobAuditingPolicyName: default
      databaseName: testdb
      isAzureMonitorTargetEnabled: true
      resourceGroupName: blobauditingtest-4799
      serverName: blobauditingtest-6440
      state: Enabled

When isAzureMonitorTargetEnabled is true and state is Enabled, audit events flow to Azure Monitor Logs. You must separately create Diagnostic Settings with the SQLSecurityAuditEvents category on the database. The policy itself doesn’t configure storage; it only enables the Azure Monitor destination.

Store audit logs in blob storage

Organizations with long-term retention requirements write audit logs directly to blob storage for archival or external analysis.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const extendedDatabaseBlobAuditingPolicy = new azure_native.sql.ExtendedDatabaseBlobAuditingPolicy("extendedDatabaseBlobAuditingPolicy", {
    blobAuditingPolicyName: "default",
    databaseName: "testdb",
    resourceGroupName: "blobauditingtest-4799",
    serverName: "blobauditingtest-6440",
    state: azure_native.sql.BlobAuditingPolicyState.Enabled,
    storageAccountAccessKey: "sdlfkjabc+sdlfkjsdlkfsjdfLDKFTERLKFDFKLjsdfksjdflsdkfD2342309432849328476458/3RSD==",
    storageEndpoint: "https://mystorage.blob.core.windows.net",
});
import pulumi
import pulumi_azure_native as azure_native

extended_database_blob_auditing_policy = azure_native.sql.ExtendedDatabaseBlobAuditingPolicy("extendedDatabaseBlobAuditingPolicy",
    blob_auditing_policy_name="default",
    database_name="testdb",
    resource_group_name="blobauditingtest-4799",
    server_name="blobauditingtest-6440",
    state=azure_native.sql.BlobAuditingPolicyState.ENABLED,
    storage_account_access_key="sdlfkjabc+sdlfkjsdlkfsjdfLDKFTERLKFDFKLjsdfksjdflsdkfD2342309432849328476458/3RSD==",
    storage_endpoint="https://mystorage.blob.core.windows.net")
package main

import (
	sql "github.com/pulumi/pulumi-azure-native-sdk/sql/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := sql.NewExtendedDatabaseBlobAuditingPolicy(ctx, "extendedDatabaseBlobAuditingPolicy", &sql.ExtendedDatabaseBlobAuditingPolicyArgs{
			BlobAuditingPolicyName:  pulumi.String("default"),
			DatabaseName:            pulumi.String("testdb"),
			ResourceGroupName:       pulumi.String("blobauditingtest-4799"),
			ServerName:              pulumi.String("blobauditingtest-6440"),
			State:                   sql.BlobAuditingPolicyStateEnabled,
			StorageAccountAccessKey: pulumi.String("sdlfkjabc+sdlfkjsdlkfsjdfLDKFTERLKFDFKLjsdfksjdflsdkfD2342309432849328476458/3RSD=="),
			StorageEndpoint:         pulumi.String("https://mystorage.blob.core.windows.net"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var extendedDatabaseBlobAuditingPolicy = new AzureNative.Sql.ExtendedDatabaseBlobAuditingPolicy("extendedDatabaseBlobAuditingPolicy", new()
    {
        BlobAuditingPolicyName = "default",
        DatabaseName = "testdb",
        ResourceGroupName = "blobauditingtest-4799",
        ServerName = "blobauditingtest-6440",
        State = AzureNative.Sql.BlobAuditingPolicyState.Enabled,
        StorageAccountAccessKey = "sdlfkjabc+sdlfkjsdlkfsjdfLDKFTERLKFDFKLjsdfksjdflsdkfD2342309432849328476458/3RSD==",
        StorageEndpoint = "https://mystorage.blob.core.windows.net",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.sql.ExtendedDatabaseBlobAuditingPolicy;
import com.pulumi.azurenative.sql.ExtendedDatabaseBlobAuditingPolicyArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var extendedDatabaseBlobAuditingPolicy = new ExtendedDatabaseBlobAuditingPolicy("extendedDatabaseBlobAuditingPolicy", ExtendedDatabaseBlobAuditingPolicyArgs.builder()
            .blobAuditingPolicyName("default")
            .databaseName("testdb")
            .resourceGroupName("blobauditingtest-4799")
            .serverName("blobauditingtest-6440")
            .state("Enabled")
            .storageAccountAccessKey("sdlfkjabc+sdlfkjsdlkfsjdfLDKFTERLKFDFKLjsdfksjdflsdkfD2342309432849328476458/3RSD==")
            .storageEndpoint("https://mystorage.blob.core.windows.net")
            .build());

    }
}
resources:
  extendedDatabaseBlobAuditingPolicy:
    type: azure-native:sql:ExtendedDatabaseBlobAuditingPolicy
    properties:
      blobAuditingPolicyName: default
      databaseName: testdb
      resourceGroupName: blobauditingtest-4799
      serverName: blobauditingtest-6440
      state: Enabled
      storageAccountAccessKey: sdlfkjabc+sdlfkjsdlkfsjdfLDKFTERLKFDFKLjsdfksjdflsdkfD2342309432849328476458/3RSD==
      storageEndpoint: https://mystorage.blob.core.windows.net

The storageEndpoint property points to your blob storage account, and storageAccountAccessKey provides authentication. When state is Enabled with a storage endpoint, audit events write to blob storage. This configuration uses access key authentication; Managed Identity authentication is available but not shown here.

Configure selective auditing with action groups and filters

Security teams often need granular control over what gets audited, filtering by specific actions or SQL predicates to reduce log volume.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const extendedDatabaseBlobAuditingPolicy = new azure_native.sql.ExtendedDatabaseBlobAuditingPolicy("extendedDatabaseBlobAuditingPolicy", {
    auditActionsAndGroups: [
        "DATABASE_LOGOUT_GROUP",
        "DATABASE_ROLE_MEMBER_CHANGE_GROUP",
        "UPDATE on database::TestDatabaseName by public",
    ],
    blobAuditingPolicyName: "default",
    databaseName: "testdb",
    isAzureMonitorTargetEnabled: true,
    isStorageSecondaryKeyInUse: false,
    predicateExpression: "statement = 'select 1'",
    queueDelayMs: 4000,
    resourceGroupName: "blobauditingtest-4799",
    retentionDays: 6,
    serverName: "blobauditingtest-6440",
    state: azure_native.sql.BlobAuditingPolicyState.Enabled,
    storageAccountAccessKey: "sdlfkjabc+sdlfkjsdlkfsjdfLDKFTERLKFDFKLjsdfksjdflsdkfD2342309432849328476458/3RSD==",
    storageAccountSubscriptionId: "00000000-1234-0000-5678-000000000000",
    storageEndpoint: "https://mystorage.blob.core.windows.net",
});
import pulumi
import pulumi_azure_native as azure_native

extended_database_blob_auditing_policy = azure_native.sql.ExtendedDatabaseBlobAuditingPolicy("extendedDatabaseBlobAuditingPolicy",
    audit_actions_and_groups=[
        "DATABASE_LOGOUT_GROUP",
        "DATABASE_ROLE_MEMBER_CHANGE_GROUP",
        "UPDATE on database::TestDatabaseName by public",
    ],
    blob_auditing_policy_name="default",
    database_name="testdb",
    is_azure_monitor_target_enabled=True,
    is_storage_secondary_key_in_use=False,
    predicate_expression="statement = 'select 1'",
    queue_delay_ms=4000,
    resource_group_name="blobauditingtest-4799",
    retention_days=6,
    server_name="blobauditingtest-6440",
    state=azure_native.sql.BlobAuditingPolicyState.ENABLED,
    storage_account_access_key="sdlfkjabc+sdlfkjsdlkfsjdfLDKFTERLKFDFKLjsdfksjdflsdkfD2342309432849328476458/3RSD==",
    storage_account_subscription_id="00000000-1234-0000-5678-000000000000",
    storage_endpoint="https://mystorage.blob.core.windows.net")
package main

import (
	sql "github.com/pulumi/pulumi-azure-native-sdk/sql/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := sql.NewExtendedDatabaseBlobAuditingPolicy(ctx, "extendedDatabaseBlobAuditingPolicy", &sql.ExtendedDatabaseBlobAuditingPolicyArgs{
			AuditActionsAndGroups: pulumi.StringArray{
				pulumi.String("DATABASE_LOGOUT_GROUP"),
				pulumi.String("DATABASE_ROLE_MEMBER_CHANGE_GROUP"),
				pulumi.String("UPDATE on database::TestDatabaseName by public"),
			},
			BlobAuditingPolicyName:       pulumi.String("default"),
			DatabaseName:                 pulumi.String("testdb"),
			IsAzureMonitorTargetEnabled:  pulumi.Bool(true),
			IsStorageSecondaryKeyInUse:   pulumi.Bool(false),
			PredicateExpression:          pulumi.String("statement = 'select 1'"),
			QueueDelayMs:                 pulumi.Int(4000),
			ResourceGroupName:            pulumi.String("blobauditingtest-4799"),
			RetentionDays:                pulumi.Int(6),
			ServerName:                   pulumi.String("blobauditingtest-6440"),
			State:                        sql.BlobAuditingPolicyStateEnabled,
			StorageAccountAccessKey:      pulumi.String("sdlfkjabc+sdlfkjsdlkfsjdfLDKFTERLKFDFKLjsdfksjdflsdkfD2342309432849328476458/3RSD=="),
			StorageAccountSubscriptionId: pulumi.String("00000000-1234-0000-5678-000000000000"),
			StorageEndpoint:              pulumi.String("https://mystorage.blob.core.windows.net"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var extendedDatabaseBlobAuditingPolicy = new AzureNative.Sql.ExtendedDatabaseBlobAuditingPolicy("extendedDatabaseBlobAuditingPolicy", new()
    {
        AuditActionsAndGroups = new[]
        {
            "DATABASE_LOGOUT_GROUP",
            "DATABASE_ROLE_MEMBER_CHANGE_GROUP",
            "UPDATE on database::TestDatabaseName by public",
        },
        BlobAuditingPolicyName = "default",
        DatabaseName = "testdb",
        IsAzureMonitorTargetEnabled = true,
        IsStorageSecondaryKeyInUse = false,
        PredicateExpression = "statement = 'select 1'",
        QueueDelayMs = 4000,
        ResourceGroupName = "blobauditingtest-4799",
        RetentionDays = 6,
        ServerName = "blobauditingtest-6440",
        State = AzureNative.Sql.BlobAuditingPolicyState.Enabled,
        StorageAccountAccessKey = "sdlfkjabc+sdlfkjsdlkfsjdfLDKFTERLKFDFKLjsdfksjdflsdkfD2342309432849328476458/3RSD==",
        StorageAccountSubscriptionId = "00000000-1234-0000-5678-000000000000",
        StorageEndpoint = "https://mystorage.blob.core.windows.net",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.sql.ExtendedDatabaseBlobAuditingPolicy;
import com.pulumi.azurenative.sql.ExtendedDatabaseBlobAuditingPolicyArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var extendedDatabaseBlobAuditingPolicy = new ExtendedDatabaseBlobAuditingPolicy("extendedDatabaseBlobAuditingPolicy", ExtendedDatabaseBlobAuditingPolicyArgs.builder()
            .auditActionsAndGroups(            
                "DATABASE_LOGOUT_GROUP",
                "DATABASE_ROLE_MEMBER_CHANGE_GROUP",
                "UPDATE on database::TestDatabaseName by public")
            .blobAuditingPolicyName("default")
            .databaseName("testdb")
            .isAzureMonitorTargetEnabled(true)
            .isStorageSecondaryKeyInUse(false)
            .predicateExpression("statement = 'select 1'")
            .queueDelayMs(4000)
            .resourceGroupName("blobauditingtest-4799")
            .retentionDays(6)
            .serverName("blobauditingtest-6440")
            .state("Enabled")
            .storageAccountAccessKey("sdlfkjabc+sdlfkjsdlkfsjdfLDKFTERLKFDFKLjsdfksjdflsdkfD2342309432849328476458/3RSD==")
            .storageAccountSubscriptionId("00000000-1234-0000-5678-000000000000")
            .storageEndpoint("https://mystorage.blob.core.windows.net")
            .build());

    }
}
resources:
  extendedDatabaseBlobAuditingPolicy:
    type: azure-native:sql:ExtendedDatabaseBlobAuditingPolicy
    properties:
      auditActionsAndGroups:
        - DATABASE_LOGOUT_GROUP
        - DATABASE_ROLE_MEMBER_CHANGE_GROUP
        - UPDATE on database::TestDatabaseName by public
      blobAuditingPolicyName: default
      databaseName: testdb
      isAzureMonitorTargetEnabled: true
      isStorageSecondaryKeyInUse: false
      predicateExpression: statement = 'select 1'
      queueDelayMs: 4000
      resourceGroupName: blobauditingtest-4799
      retentionDays: 6
      serverName: blobauditingtest-6440
      state: Enabled
      storageAccountAccessKey: sdlfkjabc+sdlfkjsdlkfsjdfLDKFTERLKFDFKLjsdfksjdflsdkfD2342309432849328476458/3RSD==
      storageAccountSubscriptionId: 00000000-1234-0000-5678-000000000000
      storageEndpoint: https://mystorage.blob.core.windows.net

The auditActionsAndGroups property specifies which database operations to capture. Action groups like DATABASE_LOGOUT_GROUP and DATABASE_ROLE_MEMBER_CHANGE_GROUP track authentication and permission changes; specific actions like “UPDATE on database::TestDatabaseName by public” target individual operations. The predicateExpression filters events by SQL conditions (here, “statement = ‘select 1’”). The queueDelayMs property controls how long audit actions can buffer before processing, and retentionDays sets how long logs remain in storage.

Beyond these examples

These snippets focus on specific auditing policy features: Azure Monitor and blob storage destinations, action groups and predicate filtering, and retention and queue delay tuning. They’re intentionally minimal rather than full compliance solutions.

The examples reference pre-existing infrastructure such as SQL servers and databases, storage accounts with access keys, and Azure Monitor Diagnostic Settings (for Azure Monitor destination). They focus on configuring the audit policy rather than provisioning the surrounding infrastructure.

To keep things focused, common auditing patterns are omitted, including:

  • Managed Identity authentication (isManagedIdentityInUse)
  • Secondary storage key usage (isStorageSecondaryKeyInUse)
  • Cross-subscription storage (storageAccountSubscriptionId)

These omissions are intentional: the goal is to illustrate how each auditing feature is wired, not provide drop-in compliance modules. See the ExtendedDatabaseBlobAuditingPolicy resource reference for all available configuration options.

Let's configure Azure SQL Database Blob Auditing Policies

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & Requirements
What's required to enable database auditing?
Set state to Enabled. You must also provide either storageEndpoint (for blob storage auditing) or set isAzureMonitorTargetEnabled to true (for Azure Monitor auditing).
What are the minimal parameters for blob storage auditing?
Set state to Enabled, provide storageEndpoint (e.g., https://MyAccount.blob.core.windows.net), and storageAccountAccessKey.
What are the minimal parameters for Azure Monitor auditing?
Set state to Enabled and isAzureMonitorTargetEnabled to true.
Audit Actions & Groups
What audit action groups are recommended?
The recommended set is BATCH_COMPLETED_GROUP, SUCCESSFUL_DATABASE_AUTHENTICATION_GROUP, and FAILED_DATABASE_AUTHENTICATION_GROUP. This combination audits all queries, stored procedures, and login attempts.
Why am I seeing very large quantities of audit records?
Using unnecessary action groups can generate excessive audit records. Choose only specific groups that cover your auditing needs rather than enabling all available groups.
Why am I getting duplicate audit logs?
Certain action groups cover all SQL statements and stored procedures. Using these comprehensive groups in combination with other groups results in duplicate audit logs.
Storage & Authentication
How do I use managed identity instead of storage account access keys?
Set isManagedIdentityInUse to true and omit storageAccountAccessKey. Prerequisites: assign the SQL Server a system-assigned managed identity in Azure Active Directory, then grant the identity ‘Storage Blob Data Contributor’ RBAC role on the storage account.
How long are audit logs retained in storage?
Configure retentionDays to specify the number of days to keep audit logs in the storage account.
What are the limits for queue delay?
queueDelayMs specifies how long (in milliseconds) before audit actions are forced to be processed. The default minimum is 1000 (1 second) and the maximum is 2,147,483,647.
Azure Monitor & Advanced Configuration
How do I send audit events to Azure Monitor?
Set state to Enabled and isAzureMonitorTargetEnabled to true. You must also manually create Diagnostic Settings with the SQLSecurityAuditEvents diagnostic logs category on the database using REST API or PowerShell.
What properties can't be changed after creation?
The following properties are immutable: blobAuditingPolicyName, databaseName, resourceGroupName, and serverName.

Using a different cloud?

Explore security guides for other cloud providers: