Configure Azure Virtual Network Subnets

The azure-native:network:Subnet resource, part of the Pulumi Azure Native provider, carves address space from a virtual network and defines how resources within that space connect to Azure services. This guide focuses on three capabilities: address prefix allocation, service endpoint configuration, and network identity control for service traffic.

Subnets belong to virtual networks and reference resource groups. Service endpoint examples may reference public IP addresses for traffic routing. The examples are intentionally small. Combine them with your own network security groups, route tables, and NAT gateways.

Create a basic subnet with address space

Most Azure networking starts by carving address space from a virtual network into subnets, with each subnet getting a CIDR block that determines capacity.

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 IP range using CIDR notation. The virtualNetworkName and resourceGroupName properties identify where the subnet lives. Without additional configuration, the subnet uses Azure’s default routing and allows all outbound traffic.

Enable service endpoints for Azure services

Applications accessing Azure Storage or SQL Database from VMs often use service endpoints to route traffic over Azure’s backbone network instead of the public internet.

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

Service endpoints change how traffic flows to Azure services. The serviceEndpoints array lists which services (like Microsoft.Storage) should receive traffic over private paths. This keeps data transfer within Azure’s network, improving security and often reducing latency.

Route service endpoint traffic through specific public IPs

Some organizations need to control which public IP addresses appear as the source when subnet traffic reaches Azure services, often for firewall allowlisting.

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 a service endpoint specifies a public IP address resource. When VMs in this subnet access the service, traffic appears to originate from that IP. This lets you configure service-side firewalls to allow specific addresses rather than entire subnet ranges.

Beyond these examples

These snippets focus on specific subnet-level features: address space allocation, service endpoint configuration, and network identity control for service endpoints. 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 the surrounding network.

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

  • Network security groups and route tables
  • NAT gateway attachment
  • Subnet delegation to Azure services
  • Private endpoint and private link policies
  • Default outbound access and sharing scope settings

These omissions are intentional: the goal is to illustrate how each subnet feature is wired, not provide drop-in network 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
What properties can't I change after creating a subnet?
Three properties are immutable: resourceGroupName, subnetName, and virtualNetworkName. Changing any of these requires recreating the subnet.
Can I update defaultOutboundAccess after creating my subnet?
No, defaultOutboundAccess can only be set at subnet creation time and cannot be updated for an existing subnet.
Why can't I set sharingScope on my subnet?
The sharingScope property requires two conditions: defaultOutboundAccess must be set to false, and the subnet must be empty (no deployed resources).
Service Endpoints & Connectivity
How do I enable service endpoints for Azure Storage?
Add a serviceEndpoints array with an entry where service is set to Microsoft.Storage.
How do I associate a public IP address with a service endpoint?
Use the networkIdentifier property within serviceEndpoints, setting id to the resource ID of your public IP address.
What's required to create a basic subnet?
You need four properties: addressPrefix (e.g., 10.0.0.0/16), resourceGroupName, subnetName, and virtualNetworkName.
Network Policies & Access Control
What are the default network policy settings for subnets?
By default, privateEndpointNetworkPolicies is set to Disabled, while privateLinkServiceNetworkPolicies is set to Enabled.
Can I share a subnet across subscriptions in my Azure AD tenant?
Yes, set sharingScope to Tenant, but only if defaultOutboundAccess is false and the subnet is empty.

Using a different cloud?

Explore networking guides for other cloud providers: