Configure Azure SQL Managed Instance Vulnerability Assessment

The azure-native:sql:ManagedInstanceVulnerabilityAssessment resource, part of the Pulumi Azure Native provider, configures vulnerability assessment for an Azure SQL Managed Instance: where scan results are stored and how scans are scheduled. This guide focuses on three capabilities: storage authentication methods, recurring scan configuration, and email notification setup.

Vulnerability assessments require an existing managed instance, storage account with a blob container, and appropriate authentication credentials. The examples are intentionally small. Combine them with your own managed instance, storage infrastructure, and security policies.

Configure vulnerability scanning with storage account keys

Most vulnerability assessment deployments start with a storage account for scan results and use the account’s access key for authentication.

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

const managedInstanceVulnerabilityAssessment = new azure_native.sql.ManagedInstanceVulnerabilityAssessment("managedInstanceVulnerabilityAssessment", {
    managedInstanceName: "vulnerabilityaseessmenttest-6440",
    resourceGroupName: "vulnerabilityaseessmenttest-4799",
    storageAccountAccessKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    storageContainerPath: "https://myStorage.blob.core.windows.net/vulnerability-assessment/",
    vulnerabilityAssessmentName: "default",
});
import pulumi
import pulumi_azure_native as azure_native

managed_instance_vulnerability_assessment = azure_native.sql.ManagedInstanceVulnerabilityAssessment("managedInstanceVulnerabilityAssessment",
    managed_instance_name="vulnerabilityaseessmenttest-6440",
    resource_group_name="vulnerabilityaseessmenttest-4799",
    storage_account_access_key="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    storage_container_path="https://myStorage.blob.core.windows.net/vulnerability-assessment/",
    vulnerability_assessment_name="default")
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.NewManagedInstanceVulnerabilityAssessment(ctx, "managedInstanceVulnerabilityAssessment", &sql.ManagedInstanceVulnerabilityAssessmentArgs{
			ManagedInstanceName:         pulumi.String("vulnerabilityaseessmenttest-6440"),
			ResourceGroupName:           pulumi.String("vulnerabilityaseessmenttest-4799"),
			StorageAccountAccessKey:     pulumi.String("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),
			StorageContainerPath:        pulumi.String("https://myStorage.blob.core.windows.net/vulnerability-assessment/"),
			VulnerabilityAssessmentName: pulumi.String("default"),
		})
		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 managedInstanceVulnerabilityAssessment = new AzureNative.Sql.ManagedInstanceVulnerabilityAssessment("managedInstanceVulnerabilityAssessment", new()
    {
        ManagedInstanceName = "vulnerabilityaseessmenttest-6440",
        ResourceGroupName = "vulnerabilityaseessmenttest-4799",
        StorageAccountAccessKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        StorageContainerPath = "https://myStorage.blob.core.windows.net/vulnerability-assessment/",
        VulnerabilityAssessmentName = "default",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.sql.ManagedInstanceVulnerabilityAssessment;
import com.pulumi.azurenative.sql.ManagedInstanceVulnerabilityAssessmentArgs;
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 managedInstanceVulnerabilityAssessment = new ManagedInstanceVulnerabilityAssessment("managedInstanceVulnerabilityAssessment", ManagedInstanceVulnerabilityAssessmentArgs.builder()
            .managedInstanceName("vulnerabilityaseessmenttest-6440")
            .resourceGroupName("vulnerabilityaseessmenttest-4799")
            .storageAccountAccessKey("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
            .storageContainerPath("https://myStorage.blob.core.windows.net/vulnerability-assessment/")
            .vulnerabilityAssessmentName("default")
            .build());

    }
}
resources:
  managedInstanceVulnerabilityAssessment:
    type: azure-native:sql:ManagedInstanceVulnerabilityAssessment
    properties:
      managedInstanceName: vulnerabilityaseessmenttest-6440
      resourceGroupName: vulnerabilityaseessmenttest-4799
      storageAccountAccessKey: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      storageContainerPath: https://myStorage.blob.core.windows.net/vulnerability-assessment/
      vulnerabilityAssessmentName: default

The storageContainerPath points to a blob container where scan results are written. The storageAccountAccessKey provides full access to the storage account. This approach works when the storage account is publicly accessible or not behind a VNet. The vulnerabilityAssessmentName is typically set to “default” as only one assessment can exist per managed instance.

Configure vulnerability scanning with SAS tokens

When storage accounts sit behind VNets or firewalls, SAS tokens provide scoped write access to specific containers without exposing the full account key.

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

const managedInstanceVulnerabilityAssessment = new azure_native.sql.ManagedInstanceVulnerabilityAssessment("managedInstanceVulnerabilityAssessment", {
    managedInstanceName: "vulnerabilityaseessmenttest-6440",
    resourceGroupName: "vulnerabilityaseessmenttest-4799",
    storageContainerPath: "https://myStorage.blob.core.windows.net/vulnerability-assessment/",
    storageContainerSasKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    vulnerabilityAssessmentName: "default",
});
import pulumi
import pulumi_azure_native as azure_native

managed_instance_vulnerability_assessment = azure_native.sql.ManagedInstanceVulnerabilityAssessment("managedInstanceVulnerabilityAssessment",
    managed_instance_name="vulnerabilityaseessmenttest-6440",
    resource_group_name="vulnerabilityaseessmenttest-4799",
    storage_container_path="https://myStorage.blob.core.windows.net/vulnerability-assessment/",
    storage_container_sas_key="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    vulnerability_assessment_name="default")
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.NewManagedInstanceVulnerabilityAssessment(ctx, "managedInstanceVulnerabilityAssessment", &sql.ManagedInstanceVulnerabilityAssessmentArgs{
			ManagedInstanceName:         pulumi.String("vulnerabilityaseessmenttest-6440"),
			ResourceGroupName:           pulumi.String("vulnerabilityaseessmenttest-4799"),
			StorageContainerPath:        pulumi.String("https://myStorage.blob.core.windows.net/vulnerability-assessment/"),
			StorageContainerSasKey:      pulumi.String("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),
			VulnerabilityAssessmentName: pulumi.String("default"),
		})
		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 managedInstanceVulnerabilityAssessment = new AzureNative.Sql.ManagedInstanceVulnerabilityAssessment("managedInstanceVulnerabilityAssessment", new()
    {
        ManagedInstanceName = "vulnerabilityaseessmenttest-6440",
        ResourceGroupName = "vulnerabilityaseessmenttest-4799",
        StorageContainerPath = "https://myStorage.blob.core.windows.net/vulnerability-assessment/",
        StorageContainerSasKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        VulnerabilityAssessmentName = "default",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.sql.ManagedInstanceVulnerabilityAssessment;
import com.pulumi.azurenative.sql.ManagedInstanceVulnerabilityAssessmentArgs;
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 managedInstanceVulnerabilityAssessment = new ManagedInstanceVulnerabilityAssessment("managedInstanceVulnerabilityAssessment", ManagedInstanceVulnerabilityAssessmentArgs.builder()
            .managedInstanceName("vulnerabilityaseessmenttest-6440")
            .resourceGroupName("vulnerabilityaseessmenttest-4799")
            .storageContainerPath("https://myStorage.blob.core.windows.net/vulnerability-assessment/")
            .storageContainerSasKey("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
            .vulnerabilityAssessmentName("default")
            .build());

    }
}
resources:
  managedInstanceVulnerabilityAssessment:
    type: azure-native:sql:ManagedInstanceVulnerabilityAssessment
    properties:
      managedInstanceName: vulnerabilityaseessmenttest-6440
      resourceGroupName: vulnerabilityaseessmenttest-4799
      storageContainerPath: https://myStorage.blob.core.windows.net/vulnerability-assessment/
      storageContainerSasKey: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      vulnerabilityAssessmentName: default

The storageContainerSasKey replaces the storage account access key with a time-limited, container-scoped token. This provides more granular security control and works with storage accounts behind network restrictions. You must generate the SAS token separately with write permissions to the specified container.

Enable recurring scans with email notifications

Production environments typically run vulnerability scans on a schedule and notify security teams when new issues are detected.

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

const managedInstanceVulnerabilityAssessment = new azure_native.sql.ManagedInstanceVulnerabilityAssessment("managedInstanceVulnerabilityAssessment", {
    managedInstanceName: "vulnerabilityaseessmenttest-6440",
    recurringScans: {
        emailSubscriptionAdmins: true,
        emails: [
            "email1@mail.com",
            "email2@mail.com",
        ],
        isEnabled: true,
    },
    resourceGroupName: "vulnerabilityaseessmenttest-4799",
    storageAccountAccessKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    storageContainerPath: "https://myStorage.blob.core.windows.net/vulnerability-assessment/",
    storageContainerSasKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    vulnerabilityAssessmentName: "default",
});
import pulumi
import pulumi_azure_native as azure_native

managed_instance_vulnerability_assessment = azure_native.sql.ManagedInstanceVulnerabilityAssessment("managedInstanceVulnerabilityAssessment",
    managed_instance_name="vulnerabilityaseessmenttest-6440",
    recurring_scans={
        "email_subscription_admins": True,
        "emails": [
            "email1@mail.com",
            "email2@mail.com",
        ],
        "is_enabled": True,
    },
    resource_group_name="vulnerabilityaseessmenttest-4799",
    storage_account_access_key="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    storage_container_path="https://myStorage.blob.core.windows.net/vulnerability-assessment/",
    storage_container_sas_key="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    vulnerability_assessment_name="default")
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.NewManagedInstanceVulnerabilityAssessment(ctx, "managedInstanceVulnerabilityAssessment", &sql.ManagedInstanceVulnerabilityAssessmentArgs{
			ManagedInstanceName: pulumi.String("vulnerabilityaseessmenttest-6440"),
			RecurringScans: &sql.VulnerabilityAssessmentRecurringScansPropertiesArgs{
				EmailSubscriptionAdmins: pulumi.Bool(true),
				Emails: pulumi.StringArray{
					pulumi.String("email1@mail.com"),
					pulumi.String("email2@mail.com"),
				},
				IsEnabled: pulumi.Bool(true),
			},
			ResourceGroupName:           pulumi.String("vulnerabilityaseessmenttest-4799"),
			StorageAccountAccessKey:     pulumi.String("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),
			StorageContainerPath:        pulumi.String("https://myStorage.blob.core.windows.net/vulnerability-assessment/"),
			StorageContainerSasKey:      pulumi.String("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),
			VulnerabilityAssessmentName: pulumi.String("default"),
		})
		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 managedInstanceVulnerabilityAssessment = new AzureNative.Sql.ManagedInstanceVulnerabilityAssessment("managedInstanceVulnerabilityAssessment", new()
    {
        ManagedInstanceName = "vulnerabilityaseessmenttest-6440",
        RecurringScans = new AzureNative.Sql.Inputs.VulnerabilityAssessmentRecurringScansPropertiesArgs
        {
            EmailSubscriptionAdmins = true,
            Emails = new[]
            {
                "email1@mail.com",
                "email2@mail.com",
            },
            IsEnabled = true,
        },
        ResourceGroupName = "vulnerabilityaseessmenttest-4799",
        StorageAccountAccessKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        StorageContainerPath = "https://myStorage.blob.core.windows.net/vulnerability-assessment/",
        StorageContainerSasKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        VulnerabilityAssessmentName = "default",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.sql.ManagedInstanceVulnerabilityAssessment;
import com.pulumi.azurenative.sql.ManagedInstanceVulnerabilityAssessmentArgs;
import com.pulumi.azurenative.sql.inputs.VulnerabilityAssessmentRecurringScansPropertiesArgs;
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 managedInstanceVulnerabilityAssessment = new ManagedInstanceVulnerabilityAssessment("managedInstanceVulnerabilityAssessment", ManagedInstanceVulnerabilityAssessmentArgs.builder()
            .managedInstanceName("vulnerabilityaseessmenttest-6440")
            .recurringScans(VulnerabilityAssessmentRecurringScansPropertiesArgs.builder()
                .emailSubscriptionAdmins(true)
                .emails(                
                    "email1@mail.com",
                    "email2@mail.com")
                .isEnabled(true)
                .build())
            .resourceGroupName("vulnerabilityaseessmenttest-4799")
            .storageAccountAccessKey("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
            .storageContainerPath("https://myStorage.blob.core.windows.net/vulnerability-assessment/")
            .storageContainerSasKey("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
            .vulnerabilityAssessmentName("default")
            .build());

    }
}
resources:
  managedInstanceVulnerabilityAssessment:
    type: azure-native:sql:ManagedInstanceVulnerabilityAssessment
    properties:
      managedInstanceName: vulnerabilityaseessmenttest-6440
      recurringScans:
        emailSubscriptionAdmins: true
        emails:
          - email1@mail.com
          - email2@mail.com
        isEnabled: true
      resourceGroupName: vulnerabilityaseessmenttest-4799
      storageAccountAccessKey: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      storageContainerPath: https://myStorage.blob.core.windows.net/vulnerability-assessment/
      storageContainerSasKey: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      vulnerabilityAssessmentName: default

The recurringScans block enables automated scanning. Set isEnabled to true to activate scheduled scans. The emails array specifies recipients for scan reports, and emailSubscriptionAdmins sends notifications to subscription administrators. This configuration extends the minimal setup by automating the scanning process and establishing notification channels for security findings.

Beyond these examples

These snippets focus on specific vulnerability assessment features: storage authentication and recurring scans with email notifications. They’re intentionally minimal rather than full security monitoring solutions.

The examples reference pre-existing infrastructure such as Azure SQL Managed Instance, storage account with blob container, and resource group. They focus on configuring the vulnerability assessment rather than provisioning the underlying infrastructure.

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

  • Storage account and container provisioning
  • SAS token generation and rotation
  • Managed instance creation and configuration
  • Integration with Azure Security Center or Defender

These omissions are intentional: the goal is to illustrate how vulnerability assessment features are wired, not provide drop-in security modules. See the ManagedInstanceVulnerabilityAssessment resource reference for all available configuration options.

Let's configure Azure SQL Managed Instance Vulnerability Assessment

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Storage & Authentication
How do I authenticate to the storage account for vulnerability assessments?
You have two options: use storageAccountAccessKey for the storage account key, or storageContainerSasKey for a SAS token with write access. If one isn’t specified, the other is required. Note that neither applies if your storage account is behind a Vnet or firewall.
What storage configuration is required?
You must provide storageContainerPath pointing to a blob storage container (e.g., https://myStorage.blob.core.windows.net/VaScans/), plus either storageAccountAccessKey or storageContainerSasKey for authentication.
Configuration & Scans
How do I enable recurring vulnerability scans with email notifications?
Configure recurringScans with isEnabled: true. Optionally, add an emails array for specific recipients and set emailSubscriptionAdmins: true to notify subscription admins.
Are recurring scans required?
No, recurringScans is optional. The minimal examples show vulnerability assessments without recurring scans configured.
Resource Properties
What properties can't I change after creating the vulnerability assessment?
The managedInstanceName, resourceGroupName, and vulnerabilityAssessmentName properties are immutable and cannot be modified after creation.
What should I name my vulnerability assessment?
All examples use "default" as the vulnerabilityAssessmentName, which appears to be the standard convention.

Using a different cloud?

Explore security guides for other cloud providers: