Configure Azure SQL Database Blob Auditing Policies

The azure-native:sql:DatabaseBlobAuditingPolicy resource, part of the Pulumi Azure Native provider, configures audit logging for an Azure SQL database: where events are sent, which actions are captured, and how long logs are retained. This guide focuses on three capabilities: Azure Monitor integration, blob storage archival, and action group filtering with retention controls.

Audit policies reference existing databases, servers, and storage accounts. Azure Monitor routing requires separate Diagnostic Settings configuration. The examples are intentionally small. Combine them with your own database 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 databaseBlobAuditingPolicy = new azure_native.sql.DatabaseBlobAuditingPolicy("databaseBlobAuditingPolicy", {
    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

database_blob_auditing_policy = azure_native.sql.DatabaseBlobAuditingPolicy("databaseBlobAuditingPolicy",
    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.NewDatabaseBlobAuditingPolicy(ctx, "databaseBlobAuditingPolicy", &sql.DatabaseBlobAuditingPolicyArgs{
			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 databaseBlobAuditingPolicy = new AzureNative.Sql.DatabaseBlobAuditingPolicy("databaseBlobAuditingPolicy", 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.DatabaseBlobAuditingPolicy;
import com.pulumi.azurenative.sql.DatabaseBlobAuditingPolicyArgs;
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 databaseBlobAuditingPolicy = new DatabaseBlobAuditingPolicy("databaseBlobAuditingPolicy", DatabaseBlobAuditingPolicyArgs.builder()
            .blobAuditingPolicyName("default")
            .databaseName("testdb")
            .isAzureMonitorTargetEnabled(true)
            .resourceGroupName("blobauditingtest-4799")
            .serverName("blobauditingtest-6440")
            .state("Enabled")
            .build());

    }
}
resources:
  databaseBlobAuditingPolicy:
    type: azure-native:sql:DatabaseBlobAuditingPolicy
    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. You must separately create Diagnostic Settings with the SQLSecurityAuditEvents category on the database. For server-level auditing, use the ‘master’ database as the target.

Store audit logs in blob storage

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

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

const databaseBlobAuditingPolicy = new azure_native.sql.DatabaseBlobAuditingPolicy("databaseBlobAuditingPolicy", {
    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

database_blob_auditing_policy = azure_native.sql.DatabaseBlobAuditingPolicy("databaseBlobAuditingPolicy",
    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.NewDatabaseBlobAuditingPolicy(ctx, "databaseBlobAuditingPolicy", &sql.DatabaseBlobAuditingPolicyArgs{
			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 databaseBlobAuditingPolicy = new AzureNative.Sql.DatabaseBlobAuditingPolicy("databaseBlobAuditingPolicy", 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.DatabaseBlobAuditingPolicy;
import com.pulumi.azurenative.sql.DatabaseBlobAuditingPolicyArgs;
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 databaseBlobAuditingPolicy = new DatabaseBlobAuditingPolicy("databaseBlobAuditingPolicy", DatabaseBlobAuditingPolicyArgs.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:
  databaseBlobAuditingPolicy:
    type: azure-native:sql:DatabaseBlobAuditingPolicy
    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 are written to blob storage. This configuration uses access key authentication; for managed identity, set isManagedIdentityInUse to true and omit the access key.

Configure detailed audit actions and retention

Security teams tracking specific operations need granular control over which actions are audited and how long logs persist.

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

const databaseBlobAuditingPolicy = new azure_native.sql.DatabaseBlobAuditingPolicy("databaseBlobAuditingPolicy", {
    auditActionsAndGroups: [
        "DATABASE_LOGOUT_GROUP",
        "DATABASE_ROLE_MEMBER_CHANGE_GROUP",
        "UPDATE on database::TestDatabaseName by public",
    ],
    blobAuditingPolicyName: "default",
    databaseName: "testdb",
    isAzureMonitorTargetEnabled: true,
    isStorageSecondaryKeyInUse: false,
    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

database_blob_auditing_policy = azure_native.sql.DatabaseBlobAuditingPolicy("databaseBlobAuditingPolicy",
    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,
    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.NewDatabaseBlobAuditingPolicy(ctx, "databaseBlobAuditingPolicy", &sql.DatabaseBlobAuditingPolicyArgs{
			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),
			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 databaseBlobAuditingPolicy = new AzureNative.Sql.DatabaseBlobAuditingPolicy("databaseBlobAuditingPolicy", 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,
        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.DatabaseBlobAuditingPolicy;
import com.pulumi.azurenative.sql.DatabaseBlobAuditingPolicyArgs;
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 databaseBlobAuditingPolicy = new DatabaseBlobAuditingPolicy("databaseBlobAuditingPolicy", DatabaseBlobAuditingPolicyArgs.builder()
            .auditActionsAndGroups(            
                "DATABASE_LOGOUT_GROUP",
                "DATABASE_ROLE_MEMBER_CHANGE_GROUP",
                "UPDATE on database::TestDatabaseName by public")
            .blobAuditingPolicyName("default")
            .databaseName("testdb")
            .isAzureMonitorTargetEnabled(true)
            .isStorageSecondaryKeyInUse(false)
            .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:
  databaseBlobAuditingPolicy:
    type: azure-native:sql:DatabaseBlobAuditingPolicy
    properties:
      auditActionsAndGroups:
        - DATABASE_LOGOUT_GROUP
        - DATABASE_ROLE_MEMBER_CHANGE_GROUP
        - UPDATE on database::TestDatabaseName by public
      blobAuditingPolicyName: default
      databaseName: testdb
      isAzureMonitorTargetEnabled: true
      isStorageSecondaryKeyInUse: false
      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 filters which database operations are logged. Action groups like DATABASE_LOGOUT_GROUP and DATABASE_ROLE_MEMBER_CHANGE_GROUP capture categories of activity, while specific actions like “UPDATE on database::TestDatabaseName by public” target individual operations. The retentionDays property controls how long logs remain in storage, and queueDelayMs sets the maximum delay before events are processed.

Beyond these examples

These snippets focus on specific auditing policy features: Azure Monitor and blob storage destinations, action group filtering and retention policies, and authentication methods. They’re intentionally minimal rather than full compliance solutions.

The examples reference pre-existing infrastructure such as Azure SQL databases and servers, storage accounts with blob endpoints, and Diagnostic Settings for Azure Monitor routing. 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)
  • Storage account subscription targeting (storageAccountSubscriptionId)
  • Secondary key rotation (isStorageSecondaryKeyInUse in minimal examples)
  • Custom action specifications beyond action groups

These omissions are intentional: the goal is to illustrate how each auditing feature is wired, not provide drop-in compliance modules. See the DatabaseBlobAuditingPolicy 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 & Setup
What's required when enabling the auditing policy?
When setting state to Enabled, you must provide at least one audit destination: either storageEndpoint (for blob storage) or set isAzureMonitorTargetEnabled to true (for Azure Monitor).
What are the two ways to configure audit destinations?
You can send audit logs to blob storage (using storageEndpoint and storageAccountAccessKey) or to Azure Monitor (using isAzureMonitorTargetEnabled). You can also use both simultaneously.
What properties can't be changed after creation?
The following properties are immutable: blobAuditingPolicyName, databaseName, resourceGroupName, and serverName. Changing these requires recreating the resource.
Audit Actions & Groups
What's the recommended set of audit action groups?
Use this combination: BATCH_COMPLETED_GROUP, SUCCESSFUL_DATABASE_AUTHENTICATION_GROUP, and FAILED_DATABASE_AUTHENTICATION_GROUP. This audits all queries, stored procedures, and login attempts, and matches the Azure portal default.
How can I avoid duplicate audit logs?
Don’t combine BATCH_STARTED_GROUP, BATCH_COMPLETED_GROUP, or DBCC_GROUP with other action groups. These comprehensive groups cover all SQL statements and will create duplicate logs when used with other groups.
Can I audit specific actions instead of action groups?
Yes, for database auditing you can specify individual actions like SELECT, UPDATE, INSERT, DELETE, EXECUTE, RECEIVE, and REFERENCES using the format {action} ON {object} BY {principal} (e.g., UPDATE on database::TestDatabaseName by public).
Storage & Authentication
Can I use managed identity instead of storage access keys?
Yes. Don’t specify storageAccountAccessKey and the SQL server’s system-assigned managed identity will be used. Prerequisites: assign the SQL Server a system-assigned managed identity in Azure Active Directory and grant it the ‘Storage Blob Data Contributor’ RBAC role on the storage account.
How long are audit logs retained in storage?
Use retentionDays to specify the number of days to keep audit logs in the storage account. There’s no default value stated in the schema.
What does the queueDelayMs parameter control?
It specifies how long (in milliseconds) audit actions can wait before being processed. The default minimum is 1000 (1 second) and maximum is 2,147,483,647.
Azure Monitor Integration
What additional setup is needed for Azure Monitor auditing?
Besides setting isAzureMonitorTargetEnabled to true, you must create Diagnostic Settings with the ‘SQLSecurityAuditEvents’ logs category on the database using the REST API or PowerShell. For server-level audit, use the ‘master’ database.
Common Issues
Why am I getting an error when enabling the policy?
If state is Enabled, you must specify either storageEndpoint or set isAzureMonitorTargetEnabled to true. The policy requires at least one audit destination.
Why isn't managed identity authentication working?
Verify you’ve completed both prerequisites: the SQL Server must have a system-assigned managed identity in Azure Active Directory, and that identity must have the ‘Storage Blob Data Contributor’ RBAC role on the storage account.

Using a different cloud?

Explore security guides for other cloud providers: