Configure Azure Virtual Network Subnets

The azure-native:network:Subnet resource, part of the Pulumi Azure Native provider, defines a subnet within an Azure virtual network: its address range, service endpoints, and network policies. This guide focuses on three capabilities: address space allocation, service endpoint configuration, and network identity binding.

Subnets belong to virtual networks and may reference network security groups, route tables, or public IP addresses. The examples are intentionally small. Combine them with your own virtual networks, security policies, and routing configuration.

Create a basic subnet with address space

Most Azure networking starts by carving a virtual network into subnets, each with its own address range for organizing resources by tier or function.

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

const subnet = new azure_native.network.Subnet("subnet", {
    addressPrefix: "10.0.0.0/16",
    resourceGroupName: "subnet-test",
    subnetName: "subnet1",
    virtualNetworkName: "vnetname",
});
import pulumi
import pulumi_azure_native as azure_native

subnet = azure_native.network.Subnet("subnet",
    address_prefix="10.0.0.0/16",
    resource_group_name="subnet-test",
    subnet_name="subnet1",
    virtual_network_name="vnetname")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := network.NewSubnet(ctx, "subnet", &network.SubnetArgs{
			AddressPrefix:      pulumi.String("10.0.0.0/16"),
			ResourceGroupName:  pulumi.String("subnet-test"),
			SubnetName:         pulumi.String("subnet1"),
			VirtualNetworkName: pulumi.String("vnetname"),
		})
		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 subnet = new AzureNative.Network.Subnet("subnet", new()
    {
        AddressPrefix = "10.0.0.0/16",
        ResourceGroupName = "subnet-test",
        SubnetName = "subnet1",
        VirtualNetworkName = "vnetname",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.network.Subnet;
import com.pulumi.azurenative.network.SubnetArgs;
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 subnet = new Subnet("subnet", SubnetArgs.builder()
            .addressPrefix("10.0.0.0/16")
            .resourceGroupName("subnet-test")
            .subnetName("subnet1")
            .virtualNetworkName("vnetname")
            .build());

    }
}
resources:
  subnet:
    type: azure-native:network:Subnet
    properties:
      addressPrefix: 10.0.0.0/16
      resourceGroupName: subnet-test
      subnetName: subnet1
      virtualNetworkName: vnetname

The addressPrefix property defines the subnet’s IP range in CIDR notation. The virtualNetworkName and resourceGroupName properties identify where the subnet lives. Resources deployed into this subnet receive IP addresses from the specified range.

Enable service endpoints for Azure services

Applications that access Azure Storage or SQL Database from VMs can route traffic through Azure’s backbone network instead of the public internet by enabling service endpoints.

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

const subnet = new azure_native.network.Subnet("subnet", {
    addressPrefix: "10.0.0.0/16",
    resourceGroupName: "subnet-test",
    serviceEndpoints: [{
        service: "Microsoft.Storage",
    }],
    subnetName: "subnet1",
    virtualNetworkName: "vnetname",
});
import pulumi
import pulumi_azure_native as azure_native

subnet = azure_native.network.Subnet("subnet",
    address_prefix="10.0.0.0/16",
    resource_group_name="subnet-test",
    service_endpoints=[{
        "service": "Microsoft.Storage",
    }],
    subnet_name="subnet1",
    virtual_network_name="vnetname")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := network.NewSubnet(ctx, "subnet", &network.SubnetArgs{
			AddressPrefix:     pulumi.String("10.0.0.0/16"),
			ResourceGroupName: pulumi.String("subnet-test"),
			ServiceEndpoints: network.ServiceEndpointPropertiesFormatArray{
				&network.ServiceEndpointPropertiesFormatArgs{
					Service: pulumi.String("Microsoft.Storage"),
				},
			},
			SubnetName:         pulumi.String("subnet1"),
			VirtualNetworkName: pulumi.String("vnetname"),
		})
		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 subnet = new AzureNative.Network.Subnet("subnet", new()
    {
        AddressPrefix = "10.0.0.0/16",
        ResourceGroupName = "subnet-test",
        ServiceEndpoints = new[]
        {
            new AzureNative.Network.Inputs.ServiceEndpointPropertiesFormatArgs
            {
                Service = "Microsoft.Storage",
            },
        },
        SubnetName = "subnet1",
        VirtualNetworkName = "vnetname",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.network.Subnet;
import com.pulumi.azurenative.network.SubnetArgs;
import com.pulumi.azurenative.network.inputs.ServiceEndpointPropertiesFormatArgs;
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 subnet = new Subnet("subnet", SubnetArgs.builder()
            .addressPrefix("10.0.0.0/16")
            .resourceGroupName("subnet-test")
            .serviceEndpoints(ServiceEndpointPropertiesFormatArgs.builder()
                .service("Microsoft.Storage")
                .build())
            .subnetName("subnet1")
            .virtualNetworkName("vnetname")
            .build());

    }
}
resources:
  subnet:
    type: azure-native:network:Subnet
    properties:
      addressPrefix: 10.0.0.0/16
      resourceGroupName: subnet-test
      serviceEndpoints:
        - service: Microsoft.Storage
      subnetName: subnet1
      virtualNetworkName: vnetname

The serviceEndpoints property lists Azure services that should be accessible via Microsoft’s network. Setting service to “Microsoft.Storage” routes Storage traffic through Azure’s backbone, bypassing the public internet. This improves security and can reduce latency.

Bind service endpoints to specific public IPs

Some service endpoint configurations require associating the endpoint with a specific public IP address to control the source identity for outbound connections.

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

const subnet = new azure_native.network.Subnet("subnet", {
    addressPrefix: "10.0.0.0/16",
    resourceGroupName: "subnet-test",
    serviceEndpoints: [{
        networkIdentifier: {
            id: "/subscriptions/subid/resourceGroups/subnet-test/providers/Microsoft.Network/publicIPAddresses/test-ip",
        },
        service: "Microsoft.Storage",
    }],
    subnetName: "subnet1",
    virtualNetworkName: "vnetname",
});
import pulumi
import pulumi_azure_native as azure_native

subnet = azure_native.network.Subnet("subnet",
    address_prefix="10.0.0.0/16",
    resource_group_name="subnet-test",
    service_endpoints=[{
        "network_identifier": {
            "id": "/subscriptions/subid/resourceGroups/subnet-test/providers/Microsoft.Network/publicIPAddresses/test-ip",
        },
        "service": "Microsoft.Storage",
    }],
    subnet_name="subnet1",
    virtual_network_name="vnetname")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := network.NewSubnet(ctx, "subnet", &network.SubnetArgs{
			AddressPrefix:     pulumi.String("10.0.0.0/16"),
			ResourceGroupName: pulumi.String("subnet-test"),
			ServiceEndpoints: network.ServiceEndpointPropertiesFormatArray{
				&network.ServiceEndpointPropertiesFormatArgs{
					NetworkIdentifier: &network.SubResourceArgs{
						Id: pulumi.String("/subscriptions/subid/resourceGroups/subnet-test/providers/Microsoft.Network/publicIPAddresses/test-ip"),
					},
					Service: pulumi.String("Microsoft.Storage"),
				},
			},
			SubnetName:         pulumi.String("subnet1"),
			VirtualNetworkName: pulumi.String("vnetname"),
		})
		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 subnet = new AzureNative.Network.Subnet("subnet", new()
    {
        AddressPrefix = "10.0.0.0/16",
        ResourceGroupName = "subnet-test",
        ServiceEndpoints = new[]
        {
            new AzureNative.Network.Inputs.ServiceEndpointPropertiesFormatArgs
            {
                NetworkIdentifier = new AzureNative.Network.Inputs.SubResourceArgs
                {
                    Id = "/subscriptions/subid/resourceGroups/subnet-test/providers/Microsoft.Network/publicIPAddresses/test-ip",
                },
                Service = "Microsoft.Storage",
            },
        },
        SubnetName = "subnet1",
        VirtualNetworkName = "vnetname",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.network.Subnet;
import com.pulumi.azurenative.network.SubnetArgs;
import com.pulumi.azurenative.network.inputs.ServiceEndpointPropertiesFormatArgs;
import com.pulumi.azurenative.network.inputs.SubResourceArgs;
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 subnet = new Subnet("subnet", SubnetArgs.builder()
            .addressPrefix("10.0.0.0/16")
            .resourceGroupName("subnet-test")
            .serviceEndpoints(ServiceEndpointPropertiesFormatArgs.builder()
                .networkIdentifier(SubResourceArgs.builder()
                    .id("/subscriptions/subid/resourceGroups/subnet-test/providers/Microsoft.Network/publicIPAddresses/test-ip")
                    .build())
                .service("Microsoft.Storage")
                .build())
            .subnetName("subnet1")
            .virtualNetworkName("vnetname")
            .build());

    }
}
resources:
  subnet:
    type: azure-native:network:Subnet
    properties:
      addressPrefix: 10.0.0.0/16
      resourceGroupName: subnet-test
      serviceEndpoints:
        - networkIdentifier:
            id: /subscriptions/subid/resourceGroups/subnet-test/providers/Microsoft.Network/publicIPAddresses/test-ip
          service: Microsoft.Storage
      subnetName: subnet1
      virtualNetworkName: vnetname

The networkIdentifier property within serviceEndpoints binds the endpoint to a specific public IP resource. This controls the source IP address that Azure services see when traffic originates from this subnet. The id property references the public IP address resource by its full Azure resource ID.

Beyond these examples

These snippets focus on specific subnet-level features: address space allocation, service endpoint configuration, and network identity binding. They’re intentionally minimal rather than full network deployments.

The examples reference pre-existing infrastructure such as virtual networks, resource groups, and public IP addresses (for network identifier example). They focus on configuring the subnet rather than provisioning everything around it.

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

  • Network security groups and route tables
  • Subnet delegations for Azure services
  • NAT gateway associations
  • Private endpoint and private link policies
  • Default outbound access controls
  • Sharing scope for cross-subscription access

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

Let's configure Azure Virtual Network Subnets

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & Immutability
Which properties can't be changed after creating a subnet?
The resourceGroupName, subnetName, and virtualNetworkName properties are immutable and require recreating the subnet to change.
Why can't I update defaultOutboundAccess after subnet creation?
The defaultOutboundAccess property can only be set during initial subnet creation and cannot be modified afterward. Changing this setting requires recreating the subnet.
What are the requirements for setting sharingScope?
You can only set sharingScope if defaultOutboundAccess is false and the subnet is empty (no deployed resources). Both properties must be configured during subnet creation.
Service Endpoints & Connectivity
How do I configure service endpoints for my subnet?
Add a serviceEndpoints array with the desired service (e.g., Microsoft.Storage). You can optionally specify a networkIdentifier to reference a public IP address resource.
Network Policies & Security
What are the default network policy settings for subnets?
By default, privateEndpointNetworkPolicies is set to Disabled and privateLinkServiceNetworkPolicies is set to Enabled.
Address Management
What's the difference between addressPrefix and addressPrefixes?
Use addressPrefix for a single address range (e.g., 10.0.0.0/16) or addressPrefixes for multiple address ranges as an array.

Using a different cloud?

Explore networking guides for other cloud providers: