Deploy Azure AI Search Services

The azure-native:search:Service resource, part of the Pulumi Azure Native provider, provisions an Azure AI Search service: its SKU, capacity (replicas and partitions), authentication methods, and network access controls. This guide focuses on four capabilities: capacity planning with replicas and partitions, authentication configuration (Azure AD and API keys), network isolation and IP-based access control, and customer-managed key encryption.

Search services require an Azure resource group and region. Network isolation features depend on virtual networks and private endpoints. Customer-managed encryption requires Azure Key Vault. The examples are intentionally small. Combine them with your own resource groups, networking infrastructure, and Key Vault configuration.

Create a search service with capacity and tags

Most deployments start by provisioning a service with a chosen SKU, replica count, and partition count to match expected query volume and index size.

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

const service = new azure_native.search.Service("service", {
    computeType: azure_native.search.ComputeType.Default,
    hostingMode: azure_native.search.HostingMode.Default,
    location: "westus",
    partitionCount: 1,
    replicaCount: 3,
    resourceGroupName: "rg1",
    searchServiceName: "mysearchservice",
    sku: {
        name: azure_native.search.SkuName.Standard,
    },
    tags: {
        "app-name": "My e-commerce app",
    },
});
import pulumi
import pulumi_azure_native as azure_native

service = azure_native.search.Service("service",
    compute_type=azure_native.search.ComputeType.DEFAULT,
    hosting_mode=azure_native.search.HostingMode.DEFAULT,
    location="westus",
    partition_count=1,
    replica_count=3,
    resource_group_name="rg1",
    search_service_name="mysearchservice",
    sku={
        "name": azure_native.search.SkuName.STANDARD,
    },
    tags={
        "app-name": "My e-commerce app",
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := search.NewService(ctx, "service", &search.ServiceArgs{
			ComputeType:       pulumi.String(search.ComputeTypeDefault),
			HostingMode:       search.HostingModeDefault,
			Location:          pulumi.String("westus"),
			PartitionCount:    pulumi.Int(1),
			ReplicaCount:      pulumi.Int(3),
			ResourceGroupName: pulumi.String("rg1"),
			SearchServiceName: pulumi.String("mysearchservice"),
			Sku: &search.SkuArgs{
				Name: pulumi.String(search.SkuNameStandard),
			},
			Tags: pulumi.StringMap{
				"app-name": pulumi.String("My e-commerce app"),
			},
		})
		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 service = new AzureNative.Search.Service("service", new()
    {
        ComputeType = AzureNative.Search.ComputeType.Default,
        HostingMode = AzureNative.Search.HostingMode.Default,
        Location = "westus",
        PartitionCount = 1,
        ReplicaCount = 3,
        ResourceGroupName = "rg1",
        SearchServiceName = "mysearchservice",
        Sku = new AzureNative.Search.Inputs.SkuArgs
        {
            Name = AzureNative.Search.SkuName.Standard,
        },
        Tags = 
        {
            { "app-name", "My e-commerce app" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.search.Service;
import com.pulumi.azurenative.search.ServiceArgs;
import com.pulumi.azurenative.search.inputs.SkuArgs;
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 service = new Service("service", ServiceArgs.builder()
            .computeType("Default")
            .hostingMode("Default")
            .location("westus")
            .partitionCount(1)
            .replicaCount(3)
            .resourceGroupName("rg1")
            .searchServiceName("mysearchservice")
            .sku(SkuArgs.builder()
                .name("standard")
                .build())
            .tags(Map.of("app-name", "My e-commerce app"))
            .build());

    }
}
resources:
  service:
    type: azure-native:search:Service
    properties:
      computeType: Default
      hostingMode: Default
      location: westus
      partitionCount: 1
      replicaCount: 3
      resourceGroupName: rg1
      searchServiceName: mysearchservice
      sku:
        name: standard
      tags:
        app-name: My e-commerce app

The sku property determines pricing tier and capacity limits. The replicaCount property controls query throughput and availability (3 replicas provide high availability). The partitionCount property determines index storage capacity. Tags help organize resources for cost tracking and management.

Configure Azure AD authentication with fallback behavior

Services that integrate with Azure AD can control how authentication failures are handled, either returning HTTP 401 with bearer challenge or allowing fallback to API keys.

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

const service = new azure_native.search.Service("service", {
    authOptions: {
        aadOrApiKey: {
            aadAuthFailureMode: azure_native.search.AadAuthFailureMode.Http401WithBearerChallenge,
        },
    },
    computeType: azure_native.search.ComputeType.Default,
    hostingMode: azure_native.search.HostingMode.Default,
    location: "westus",
    partitionCount: 1,
    replicaCount: 3,
    resourceGroupName: "rg1",
    searchServiceName: "mysearchservice",
    sku: {
        name: azure_native.search.SkuName.Standard,
    },
    tags: {
        "app-name": "My e-commerce app",
    },
});
import pulumi
import pulumi_azure_native as azure_native

service = azure_native.search.Service("service",
    auth_options={
        "aad_or_api_key": {
            "aad_auth_failure_mode": azure_native.search.AadAuthFailureMode.HTTP401_WITH_BEARER_CHALLENGE,
        },
    },
    compute_type=azure_native.search.ComputeType.DEFAULT,
    hosting_mode=azure_native.search.HostingMode.DEFAULT,
    location="westus",
    partition_count=1,
    replica_count=3,
    resource_group_name="rg1",
    search_service_name="mysearchservice",
    sku={
        "name": azure_native.search.SkuName.STANDARD,
    },
    tags={
        "app-name": "My e-commerce app",
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := search.NewService(ctx, "service", &search.ServiceArgs{
			AuthOptions: &search.DataPlaneAuthOptionsArgs{
				AadOrApiKey: &search.DataPlaneAadOrApiKeyAuthOptionArgs{
					AadAuthFailureMode: search.AadAuthFailureModeHttp401WithBearerChallenge,
				},
			},
			ComputeType:       pulumi.String(search.ComputeTypeDefault),
			HostingMode:       search.HostingModeDefault,
			Location:          pulumi.String("westus"),
			PartitionCount:    pulumi.Int(1),
			ReplicaCount:      pulumi.Int(3),
			ResourceGroupName: pulumi.String("rg1"),
			SearchServiceName: pulumi.String("mysearchservice"),
			Sku: &search.SkuArgs{
				Name: pulumi.String(search.SkuNameStandard),
			},
			Tags: pulumi.StringMap{
				"app-name": pulumi.String("My e-commerce app"),
			},
		})
		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 service = new AzureNative.Search.Service("service", new()
    {
        AuthOptions = new AzureNative.Search.Inputs.DataPlaneAuthOptionsArgs
        {
            AadOrApiKey = new AzureNative.Search.Inputs.DataPlaneAadOrApiKeyAuthOptionArgs
            {
                AadAuthFailureMode = AzureNative.Search.AadAuthFailureMode.Http401WithBearerChallenge,
            },
        },
        ComputeType = AzureNative.Search.ComputeType.Default,
        HostingMode = AzureNative.Search.HostingMode.Default,
        Location = "westus",
        PartitionCount = 1,
        ReplicaCount = 3,
        ResourceGroupName = "rg1",
        SearchServiceName = "mysearchservice",
        Sku = new AzureNative.Search.Inputs.SkuArgs
        {
            Name = AzureNative.Search.SkuName.Standard,
        },
        Tags = 
        {
            { "app-name", "My e-commerce app" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.search.Service;
import com.pulumi.azurenative.search.ServiceArgs;
import com.pulumi.azurenative.search.inputs.DataPlaneAuthOptionsArgs;
import com.pulumi.azurenative.search.inputs.DataPlaneAadOrApiKeyAuthOptionArgs;
import com.pulumi.azurenative.search.inputs.SkuArgs;
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 service = new Service("service", ServiceArgs.builder()
            .authOptions(DataPlaneAuthOptionsArgs.builder()
                .aadOrApiKey(DataPlaneAadOrApiKeyAuthOptionArgs.builder()
                    .aadAuthFailureMode("http401WithBearerChallenge")
                    .build())
                .build())
            .computeType("Default")
            .hostingMode("Default")
            .location("westus")
            .partitionCount(1)
            .replicaCount(3)
            .resourceGroupName("rg1")
            .searchServiceName("mysearchservice")
            .sku(SkuArgs.builder()
                .name("standard")
                .build())
            .tags(Map.of("app-name", "My e-commerce app"))
            .build());

    }
}
resources:
  service:
    type: azure-native:search:Service
    properties:
      authOptions:
        aadOrApiKey:
          aadAuthFailureMode: http401WithBearerChallenge
      computeType: Default
      hostingMode: Default
      location: westus
      partitionCount: 1
      replicaCount: 3
      resourceGroupName: rg1
      searchServiceName: mysearchservice
      sku:
        name: standard
      tags:
        app-name: My e-commerce app

The authOptions property defines data plane authentication behavior. The aadOrApiKey configuration enables both Azure AD and API key authentication. The aadAuthFailureMode property controls what happens when Azure AD authentication fails: Http401WithBearerChallenge returns a 401 response with WWW-Authenticate header, prompting clients to retry with proper credentials.

Disable API key authentication entirely

Organizations with strict security policies often require Azure AD-only authentication, blocking API key access to the search service data plane.

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

const service = new azure_native.search.Service("service", {
    computeType: azure_native.search.ComputeType.Default,
    disableLocalAuth: true,
    hostingMode: azure_native.search.HostingMode.Default,
    location: "westus",
    partitionCount: 1,
    replicaCount: 3,
    resourceGroupName: "rg1",
    searchServiceName: "mysearchservice",
    sku: {
        name: azure_native.search.SkuName.Standard,
    },
    tags: {
        "app-name": "My e-commerce app",
    },
});
import pulumi
import pulumi_azure_native as azure_native

service = azure_native.search.Service("service",
    compute_type=azure_native.search.ComputeType.DEFAULT,
    disable_local_auth=True,
    hosting_mode=azure_native.search.HostingMode.DEFAULT,
    location="westus",
    partition_count=1,
    replica_count=3,
    resource_group_name="rg1",
    search_service_name="mysearchservice",
    sku={
        "name": azure_native.search.SkuName.STANDARD,
    },
    tags={
        "app-name": "My e-commerce app",
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := search.NewService(ctx, "service", &search.ServiceArgs{
			ComputeType:       pulumi.String(search.ComputeTypeDefault),
			DisableLocalAuth:  pulumi.Bool(true),
			HostingMode:       search.HostingModeDefault,
			Location:          pulumi.String("westus"),
			PartitionCount:    pulumi.Int(1),
			ReplicaCount:      pulumi.Int(3),
			ResourceGroupName: pulumi.String("rg1"),
			SearchServiceName: pulumi.String("mysearchservice"),
			Sku: &search.SkuArgs{
				Name: pulumi.String(search.SkuNameStandard),
			},
			Tags: pulumi.StringMap{
				"app-name": pulumi.String("My e-commerce app"),
			},
		})
		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 service = new AzureNative.Search.Service("service", new()
    {
        ComputeType = AzureNative.Search.ComputeType.Default,
        DisableLocalAuth = true,
        HostingMode = AzureNative.Search.HostingMode.Default,
        Location = "westus",
        PartitionCount = 1,
        ReplicaCount = 3,
        ResourceGroupName = "rg1",
        SearchServiceName = "mysearchservice",
        Sku = new AzureNative.Search.Inputs.SkuArgs
        {
            Name = AzureNative.Search.SkuName.Standard,
        },
        Tags = 
        {
            { "app-name", "My e-commerce app" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.search.Service;
import com.pulumi.azurenative.search.ServiceArgs;
import com.pulumi.azurenative.search.inputs.SkuArgs;
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 service = new Service("service", ServiceArgs.builder()
            .computeType("Default")
            .disableLocalAuth(true)
            .hostingMode("Default")
            .location("westus")
            .partitionCount(1)
            .replicaCount(3)
            .resourceGroupName("rg1")
            .searchServiceName("mysearchservice")
            .sku(SkuArgs.builder()
                .name("standard")
                .build())
            .tags(Map.of("app-name", "My e-commerce app"))
            .build());

    }
}
resources:
  service:
    type: azure-native:search:Service
    properties:
      computeType: Default
      disableLocalAuth: true
      hostingMode: Default
      location: westus
      partitionCount: 1
      replicaCount: 3
      resourceGroupName: rg1
      searchServiceName: mysearchservice
      sku:
        name: standard
      tags:
        app-name: My e-commerce app

Setting disableLocalAuth to true blocks all API key authentication. Clients must use Azure AD tokens to access the service. This property cannot be combined with authOptions; choose one authentication strategy.

Restrict access to private endpoints only

Services that handle sensitive data often disable public internet access and require connections through private endpoints within a virtual network.

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

const service = new azure_native.search.Service("service", {
    computeType: azure_native.search.ComputeType.Default,
    hostingMode: azure_native.search.HostingMode.Default,
    location: "westus",
    partitionCount: 1,
    publicNetworkAccess: azure_native.search.PublicNetworkAccess.Disabled,
    replicaCount: 3,
    resourceGroupName: "rg1",
    searchServiceName: "mysearchservice",
    sku: {
        name: azure_native.search.SkuName.Standard,
    },
    tags: {
        "app-name": "My e-commerce app",
    },
});
import pulumi
import pulumi_azure_native as azure_native

service = azure_native.search.Service("service",
    compute_type=azure_native.search.ComputeType.DEFAULT,
    hosting_mode=azure_native.search.HostingMode.DEFAULT,
    location="westus",
    partition_count=1,
    public_network_access=azure_native.search.PublicNetworkAccess.DISABLED,
    replica_count=3,
    resource_group_name="rg1",
    search_service_name="mysearchservice",
    sku={
        "name": azure_native.search.SkuName.STANDARD,
    },
    tags={
        "app-name": "My e-commerce app",
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := search.NewService(ctx, "service", &search.ServiceArgs{
			ComputeType:         pulumi.String(search.ComputeTypeDefault),
			HostingMode:         search.HostingModeDefault,
			Location:            pulumi.String("westus"),
			PartitionCount:      pulumi.Int(1),
			PublicNetworkAccess: pulumi.String(search.PublicNetworkAccessDisabled),
			ReplicaCount:        pulumi.Int(3),
			ResourceGroupName:   pulumi.String("rg1"),
			SearchServiceName:   pulumi.String("mysearchservice"),
			Sku: &search.SkuArgs{
				Name: pulumi.String(search.SkuNameStandard),
			},
			Tags: pulumi.StringMap{
				"app-name": pulumi.String("My e-commerce app"),
			},
		})
		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 service = new AzureNative.Search.Service("service", new()
    {
        ComputeType = AzureNative.Search.ComputeType.Default,
        HostingMode = AzureNative.Search.HostingMode.Default,
        Location = "westus",
        PartitionCount = 1,
        PublicNetworkAccess = AzureNative.Search.PublicNetworkAccess.Disabled,
        ReplicaCount = 3,
        ResourceGroupName = "rg1",
        SearchServiceName = "mysearchservice",
        Sku = new AzureNative.Search.Inputs.SkuArgs
        {
            Name = AzureNative.Search.SkuName.Standard,
        },
        Tags = 
        {
            { "app-name", "My e-commerce app" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.search.Service;
import com.pulumi.azurenative.search.ServiceArgs;
import com.pulumi.azurenative.search.inputs.SkuArgs;
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 service = new Service("service", ServiceArgs.builder()
            .computeType("Default")
            .hostingMode("Default")
            .location("westus")
            .partitionCount(1)
            .publicNetworkAccess("Disabled")
            .replicaCount(3)
            .resourceGroupName("rg1")
            .searchServiceName("mysearchservice")
            .sku(SkuArgs.builder()
                .name("standard")
                .build())
            .tags(Map.of("app-name", "My e-commerce app"))
            .build());

    }
}
resources:
  service:
    type: azure-native:search:Service
    properties:
      computeType: Default
      hostingMode: Default
      location: westus
      partitionCount: 1
      publicNetworkAccess: Disabled
      replicaCount: 3
      resourceGroupName: rg1
      searchServiceName: mysearchservice
      sku:
        name: standard
      tags:
        app-name: My e-commerce app

The publicNetworkAccess property controls whether the service accepts connections from the public internet. Setting it to Disabled blocks all public access; clients must connect through private endpoints. Private endpoint connections appear in the privateEndpointConnections output property after creation.

Allow access from specific IP addresses

When private endpoints aren’t feasible, services can restrict public access to known IP addresses or CIDR ranges for on-premises networks or specific cloud resources.

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

const service = new azure_native.search.Service("service", {
    computeType: azure_native.search.ComputeType.Default,
    hostingMode: azure_native.search.HostingMode.Default,
    location: "westus",
    networkRuleSet: {
        ipRules: [
            {
                value: "123.4.5.6",
            },
            {
                value: "123.4.6.0/18",
            },
        ],
    },
    partitionCount: 1,
    replicaCount: 1,
    resourceGroupName: "rg1",
    searchServiceName: "mysearchservice",
    sku: {
        name: azure_native.search.SkuName.Standard,
    },
    tags: {
        "app-name": "My e-commerce app",
    },
});
import pulumi
import pulumi_azure_native as azure_native

service = azure_native.search.Service("service",
    compute_type=azure_native.search.ComputeType.DEFAULT,
    hosting_mode=azure_native.search.HostingMode.DEFAULT,
    location="westus",
    network_rule_set={
        "ip_rules": [
            {
                "value": "123.4.5.6",
            },
            {
                "value": "123.4.6.0/18",
            },
        ],
    },
    partition_count=1,
    replica_count=1,
    resource_group_name="rg1",
    search_service_name="mysearchservice",
    sku={
        "name": azure_native.search.SkuName.STANDARD,
    },
    tags={
        "app-name": "My e-commerce app",
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := search.NewService(ctx, "service", &search.ServiceArgs{
			ComputeType: pulumi.String(search.ComputeTypeDefault),
			HostingMode: search.HostingModeDefault,
			Location:    pulumi.String("westus"),
			NetworkRuleSet: &search.NetworkRuleSetArgs{
				IpRules: search.IpRuleArray{
					&search.IpRuleArgs{
						Value: pulumi.String("123.4.5.6"),
					},
					&search.IpRuleArgs{
						Value: pulumi.String("123.4.6.0/18"),
					},
				},
			},
			PartitionCount:    pulumi.Int(1),
			ReplicaCount:      pulumi.Int(1),
			ResourceGroupName: pulumi.String("rg1"),
			SearchServiceName: pulumi.String("mysearchservice"),
			Sku: &search.SkuArgs{
				Name: pulumi.String(search.SkuNameStandard),
			},
			Tags: pulumi.StringMap{
				"app-name": pulumi.String("My e-commerce app"),
			},
		})
		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 service = new AzureNative.Search.Service("service", new()
    {
        ComputeType = AzureNative.Search.ComputeType.Default,
        HostingMode = AzureNative.Search.HostingMode.Default,
        Location = "westus",
        NetworkRuleSet = new AzureNative.Search.Inputs.NetworkRuleSetArgs
        {
            IpRules = new[]
            {
                new AzureNative.Search.Inputs.IpRuleArgs
                {
                    Value = "123.4.5.6",
                },
                new AzureNative.Search.Inputs.IpRuleArgs
                {
                    Value = "123.4.6.0/18",
                },
            },
        },
        PartitionCount = 1,
        ReplicaCount = 1,
        ResourceGroupName = "rg1",
        SearchServiceName = "mysearchservice",
        Sku = new AzureNative.Search.Inputs.SkuArgs
        {
            Name = AzureNative.Search.SkuName.Standard,
        },
        Tags = 
        {
            { "app-name", "My e-commerce app" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.search.Service;
import com.pulumi.azurenative.search.ServiceArgs;
import com.pulumi.azurenative.search.inputs.NetworkRuleSetArgs;
import com.pulumi.azurenative.search.inputs.SkuArgs;
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 service = new Service("service", ServiceArgs.builder()
            .computeType("Default")
            .hostingMode("Default")
            .location("westus")
            .networkRuleSet(NetworkRuleSetArgs.builder()
                .ipRules(                
                    IpRuleArgs.builder()
                        .value("123.4.5.6")
                        .build(),
                    IpRuleArgs.builder()
                        .value("123.4.6.0/18")
                        .build())
                .build())
            .partitionCount(1)
            .replicaCount(1)
            .resourceGroupName("rg1")
            .searchServiceName("mysearchservice")
            .sku(SkuArgs.builder()
                .name("standard")
                .build())
            .tags(Map.of("app-name", "My e-commerce app"))
            .build());

    }
}
resources:
  service:
    type: azure-native:search:Service
    properties:
      computeType: Default
      hostingMode: Default
      location: westus
      networkRuleSet:
        ipRules:
          - value: 123.4.5.6
          - value: 123.4.6.0/18
      partitionCount: 1
      replicaCount: 1
      resourceGroupName: rg1
      searchServiceName: mysearchservice
      sku:
        name: standard
      tags:
        app-name: My e-commerce app

The networkRuleSet property defines IP-based access controls. The ipRules array accepts individual IP addresses or CIDR ranges. Only traffic from these addresses can reach the service over the public internet. This provides a middle ground between fully public and fully private access.

Enforce customer-managed key encryption

Compliance requirements often mandate that all data at rest be encrypted with customer-managed keys stored in Azure Key Vault.

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

const service = new azure_native.search.Service("service", {
    computeType: azure_native.search.ComputeType.Default,
    encryptionWithCmk: {
        enforcement: azure_native.search.SearchEncryptionWithCmk.Enabled,
    },
    hostingMode: azure_native.search.HostingMode.Default,
    location: "westus",
    partitionCount: 1,
    replicaCount: 3,
    resourceGroupName: "rg1",
    searchServiceName: "mysearchservice",
    sku: {
        name: azure_native.search.SkuName.Standard,
    },
    tags: {
        "app-name": "My e-commerce app",
    },
});
import pulumi
import pulumi_azure_native as azure_native

service = azure_native.search.Service("service",
    compute_type=azure_native.search.ComputeType.DEFAULT,
    encryption_with_cmk={
        "enforcement": azure_native.search.SearchEncryptionWithCmk.ENABLED,
    },
    hosting_mode=azure_native.search.HostingMode.DEFAULT,
    location="westus",
    partition_count=1,
    replica_count=3,
    resource_group_name="rg1",
    search_service_name="mysearchservice",
    sku={
        "name": azure_native.search.SkuName.STANDARD,
    },
    tags={
        "app-name": "My e-commerce app",
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := search.NewService(ctx, "service", &search.ServiceArgs{
			ComputeType: pulumi.String(search.ComputeTypeDefault),
			EncryptionWithCmk: &search.EncryptionWithCmkArgs{
				Enforcement: search.SearchEncryptionWithCmkEnabled,
			},
			HostingMode:       search.HostingModeDefault,
			Location:          pulumi.String("westus"),
			PartitionCount:    pulumi.Int(1),
			ReplicaCount:      pulumi.Int(3),
			ResourceGroupName: pulumi.String("rg1"),
			SearchServiceName: pulumi.String("mysearchservice"),
			Sku: &search.SkuArgs{
				Name: pulumi.String(search.SkuNameStandard),
			},
			Tags: pulumi.StringMap{
				"app-name": pulumi.String("My e-commerce app"),
			},
		})
		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 service = new AzureNative.Search.Service("service", new()
    {
        ComputeType = AzureNative.Search.ComputeType.Default,
        EncryptionWithCmk = new AzureNative.Search.Inputs.EncryptionWithCmkArgs
        {
            Enforcement = AzureNative.Search.SearchEncryptionWithCmk.Enabled,
        },
        HostingMode = AzureNative.Search.HostingMode.Default,
        Location = "westus",
        PartitionCount = 1,
        ReplicaCount = 3,
        ResourceGroupName = "rg1",
        SearchServiceName = "mysearchservice",
        Sku = new AzureNative.Search.Inputs.SkuArgs
        {
            Name = AzureNative.Search.SkuName.Standard,
        },
        Tags = 
        {
            { "app-name", "My e-commerce app" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.search.Service;
import com.pulumi.azurenative.search.ServiceArgs;
import com.pulumi.azurenative.search.inputs.EncryptionWithCmkArgs;
import com.pulumi.azurenative.search.inputs.SkuArgs;
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 service = new Service("service", ServiceArgs.builder()
            .computeType("Default")
            .encryptionWithCmk(EncryptionWithCmkArgs.builder()
                .enforcement("Enabled")
                .build())
            .hostingMode("Default")
            .location("westus")
            .partitionCount(1)
            .replicaCount(3)
            .resourceGroupName("rg1")
            .searchServiceName("mysearchservice")
            .sku(SkuArgs.builder()
                .name("standard")
                .build())
            .tags(Map.of("app-name", "My e-commerce app"))
            .build());

    }
}
resources:
  service:
    type: azure-native:search:Service
    properties:
      computeType: Default
      encryptionWithCmk:
        enforcement: Enabled
      hostingMode: Default
      location: westus
      partitionCount: 1
      replicaCount: 3
      resourceGroupName: rg1
      searchServiceName: mysearchservice
      sku:
        name: standard
      tags:
        app-name: My e-commerce app

The encryptionWithCmk property controls encryption policy for service resources like indexes. Setting enforcement to Enabled requires all encrypted resources to use customer-managed keys from Azure Key Vault. The service must have a managed identity with permissions to access the Key Vault.

Beyond these examples

These snippets focus on specific search service features: capacity planning (replicas and partitions), authentication and network access controls, and encryption and data protection policies. They’re intentionally minimal rather than full search solutions.

The examples may reference pre-existing infrastructure such as Azure resource groups and regions, Azure Key Vault (for customer-managed keys), and virtual networks and private endpoints (for network isolation). They focus on configuring the search service rather than provisioning everything around it.

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

  • Semantic search configuration (semanticSearch property)
  • High-density hosting for standard3 SKU (hostingMode)
  • Azure service bypass rules (networkRuleSet.bypass)
  • Data exfiltration protection policies

These omissions are intentional: the goal is to illustrate how each search service feature is wired, not provide drop-in search modules. See the Azure AI Search Service resource reference for all available configuration options.

Let's deploy Azure AI Search Services

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Service Configuration & Naming
What are the naming rules for Azure AI Search services?
Service names must be 2-60 characters long, contain only lowercase letters, digits, or dashes, cannot start or end with dashes, and cannot contain consecutive dashes. The name becomes part of your service URI (https://.search.windows.net) and must be globally unique.
What properties can't be changed after creating a search service?
Three properties are immutable: searchServiceName, location, and resourceGroupName. You cannot modify these after service creation.
Authentication & Security
What's the difference between disableLocalAuth and authOptions?
These are mutually exclusive authentication configurations. Use disableLocalAuth: true to completely disable API key authentication, or use authOptions to configure specific authentication methods like Azure AD. You cannot set both simultaneously.
How do I configure Azure AD authentication?
Set authOptions.aadOrApiKey.aadAuthFailureMode to http401WithBearerChallenge to enable Azure AD authentication with bearer token challenges.
How do I enable customer-managed key encryption?
Configure encryptionWithCmk.enforcement to Enabled to enforce customer-managed key encryption for resources like indexes.
Network Access & Connectivity
How do I restrict my search service to private endpoints only?
Set publicNetworkAccess to Disabled to block all public internet traffic and allow only private endpoint connections.
How do I control network access with IP rules?
Configure networkRuleSet.ipRules with specific IP addresses or CIDR ranges. You can also set networkRuleSet.bypass to AzureServices to allow Azure service traffic while restricting other public access.
Capacity & Scaling
What are the capacity limits for partitions and replicas?
partitionCount defaults to 1 and supports values 1, 2, 3, 4, 6, or 12 for standard SKUs (1-3 for standard3 with HighDensity mode). replicaCount defaults to 1 with a range of 1-12 for standard SKUs or 1-3 for basic SKU.
What's the difference between Default and HighDensity hosting modes?
hostingMode is only applicable to standard3 SKU. HighDensity mode enables up to 3 high-density partitions supporting up to 1,000 indexes (much higher than other SKUs). All other SKUs must use Default mode.
Advanced Features
How do I enable semantic search?
Set semanticSearch to free or standard. Availability depends on your SKU and region.
How do I prevent data exfiltration?
Set dataExfiltrationProtections to BlockAll to disable all data export scenarios. This is currently the only supported value, with more granular controls planned.

Using a different cloud?

Explore analytics guides for other cloud providers: