The azure-native:network:VirtualNetworkPeering resource, part of the Pulumi Azure Native provider, establishes network connectivity between two Azure virtual networks, enabling resources to communicate privately without traversing the public internet. This guide focuses on three capabilities: full VNet peering, subnet-level peering, and address space synchronization.
Peerings connect existing virtual networks and require reciprocal configuration on both sides for bidirectional communication. The examples are intentionally small. Combine them with your own VNets, subnets, and gateway infrastructure.
Connect two virtual networks for full bidirectional access
Most deployments connect two VNets to enable private communication between resources in different networks or regions.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const virtualNetworkPeering = new azure_native.network.VirtualNetworkPeering("virtualNetworkPeering", {
allowForwardedTraffic: true,
allowGatewayTransit: false,
allowVirtualNetworkAccess: true,
remoteVirtualNetwork: {
id: "/subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2",
},
resourceGroupName: "peerTest",
useRemoteGateways: false,
virtualNetworkName: "vnet1",
virtualNetworkPeeringName: "peer",
});
import pulumi
import pulumi_azure_native as azure_native
virtual_network_peering = azure_native.network.VirtualNetworkPeering("virtualNetworkPeering",
allow_forwarded_traffic=True,
allow_gateway_transit=False,
allow_virtual_network_access=True,
remote_virtual_network={
"id": "/subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2",
},
resource_group_name="peerTest",
use_remote_gateways=False,
virtual_network_name="vnet1",
virtual_network_peering_name="peer")
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.NewVirtualNetworkPeering(ctx, "virtualNetworkPeering", &network.VirtualNetworkPeeringArgs{
AllowForwardedTraffic: pulumi.Bool(true),
AllowGatewayTransit: pulumi.Bool(false),
AllowVirtualNetworkAccess: pulumi.Bool(true),
RemoteVirtualNetwork: &network.SubResourceArgs{
Id: pulumi.String("/subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2"),
},
ResourceGroupName: pulumi.String("peerTest"),
UseRemoteGateways: pulumi.Bool(false),
VirtualNetworkName: pulumi.String("vnet1"),
VirtualNetworkPeeringName: pulumi.String("peer"),
})
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 virtualNetworkPeering = new AzureNative.Network.VirtualNetworkPeering("virtualNetworkPeering", new()
{
AllowForwardedTraffic = true,
AllowGatewayTransit = false,
AllowVirtualNetworkAccess = true,
RemoteVirtualNetwork = new AzureNative.Network.Inputs.SubResourceArgs
{
Id = "/subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2",
},
ResourceGroupName = "peerTest",
UseRemoteGateways = false,
VirtualNetworkName = "vnet1",
VirtualNetworkPeeringName = "peer",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.network.VirtualNetworkPeering;
import com.pulumi.azurenative.network.VirtualNetworkPeeringArgs;
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 virtualNetworkPeering = new VirtualNetworkPeering("virtualNetworkPeering", VirtualNetworkPeeringArgs.builder()
.allowForwardedTraffic(true)
.allowGatewayTransit(false)
.allowVirtualNetworkAccess(true)
.remoteVirtualNetwork(SubResourceArgs.builder()
.id("/subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2")
.build())
.resourceGroupName("peerTest")
.useRemoteGateways(false)
.virtualNetworkName("vnet1")
.virtualNetworkPeeringName("peer")
.build());
}
}
resources:
virtualNetworkPeering:
type: azure-native:network:VirtualNetworkPeering
properties:
allowForwardedTraffic: true
allowGatewayTransit: false
allowVirtualNetworkAccess: true
remoteVirtualNetwork:
id: /subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2
resourceGroupName: peerTest
useRemoteGateways: false
virtualNetworkName: vnet1
virtualNetworkPeeringName: peer
The remoteVirtualNetwork property references the target VNet by resource ID. The allowVirtualNetworkAccess property enables VM-to-VM communication across the peering. The allowForwardedTraffic property permits traffic from other networks to flow through this peering. Note that peerings are unidirectional; you must create a reciprocal peering from vnet2 to vnet1 for bidirectional connectivity.
Peer specific subnets instead of entire networks
When limiting connectivity scope, subnet-level peering restricts communication to specific address ranges.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const virtualNetworkPeering = new azure_native.network.VirtualNetworkPeering("virtualNetworkPeering", {
allowForwardedTraffic: true,
allowGatewayTransit: false,
allowVirtualNetworkAccess: true,
enableOnlyIPv6Peering: false,
localSubnetNames: [
"Subnet1",
"Subnet4",
],
peerCompleteVnets: false,
remoteSubnetNames: ["Subnet2"],
remoteVirtualNetwork: {
id: "/subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2",
},
resourceGroupName: "peerTest",
useRemoteGateways: false,
virtualNetworkName: "vnet1",
virtualNetworkPeeringName: "peer",
});
import pulumi
import pulumi_azure_native as azure_native
virtual_network_peering = azure_native.network.VirtualNetworkPeering("virtualNetworkPeering",
allow_forwarded_traffic=True,
allow_gateway_transit=False,
allow_virtual_network_access=True,
enable_only_i_pv6_peering=False,
local_subnet_names=[
"Subnet1",
"Subnet4",
],
peer_complete_vnets=False,
remote_subnet_names=["Subnet2"],
remote_virtual_network={
"id": "/subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2",
},
resource_group_name="peerTest",
use_remote_gateways=False,
virtual_network_name="vnet1",
virtual_network_peering_name="peer")
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.NewVirtualNetworkPeering(ctx, "virtualNetworkPeering", &network.VirtualNetworkPeeringArgs{
AllowForwardedTraffic: pulumi.Bool(true),
AllowGatewayTransit: pulumi.Bool(false),
AllowVirtualNetworkAccess: pulumi.Bool(true),
EnableOnlyIPv6Peering: pulumi.Bool(false),
LocalSubnetNames: pulumi.StringArray{
pulumi.String("Subnet1"),
pulumi.String("Subnet4"),
},
PeerCompleteVnets: pulumi.Bool(false),
RemoteSubnetNames: pulumi.StringArray{
pulumi.String("Subnet2"),
},
RemoteVirtualNetwork: &network.SubResourceArgs{
Id: pulumi.String("/subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2"),
},
ResourceGroupName: pulumi.String("peerTest"),
UseRemoteGateways: pulumi.Bool(false),
VirtualNetworkName: pulumi.String("vnet1"),
VirtualNetworkPeeringName: pulumi.String("peer"),
})
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 virtualNetworkPeering = new AzureNative.Network.VirtualNetworkPeering("virtualNetworkPeering", new()
{
AllowForwardedTraffic = true,
AllowGatewayTransit = false,
AllowVirtualNetworkAccess = true,
EnableOnlyIPv6Peering = false,
LocalSubnetNames = new[]
{
"Subnet1",
"Subnet4",
},
PeerCompleteVnets = false,
RemoteSubnetNames = new[]
{
"Subnet2",
},
RemoteVirtualNetwork = new AzureNative.Network.Inputs.SubResourceArgs
{
Id = "/subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2",
},
ResourceGroupName = "peerTest",
UseRemoteGateways = false,
VirtualNetworkName = "vnet1",
VirtualNetworkPeeringName = "peer",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.network.VirtualNetworkPeering;
import com.pulumi.azurenative.network.VirtualNetworkPeeringArgs;
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 virtualNetworkPeering = new VirtualNetworkPeering("virtualNetworkPeering", VirtualNetworkPeeringArgs.builder()
.allowForwardedTraffic(true)
.allowGatewayTransit(false)
.allowVirtualNetworkAccess(true)
.enableOnlyIPv6Peering(false)
.localSubnetNames(
"Subnet1",
"Subnet4")
.peerCompleteVnets(false)
.remoteSubnetNames("Subnet2")
.remoteVirtualNetwork(SubResourceArgs.builder()
.id("/subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2")
.build())
.resourceGroupName("peerTest")
.useRemoteGateways(false)
.virtualNetworkName("vnet1")
.virtualNetworkPeeringName("peer")
.build());
}
}
resources:
virtualNetworkPeering:
type: azure-native:network:VirtualNetworkPeering
properties:
allowForwardedTraffic: true
allowGatewayTransit: false
allowVirtualNetworkAccess: true
enableOnlyIPv6Peering: false
localSubnetNames:
- Subnet1
- Subnet4
peerCompleteVnets: false
remoteSubnetNames:
- Subnet2
remoteVirtualNetwork:
id: /subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2
resourceGroupName: peerTest
useRemoteGateways: false
virtualNetworkName: vnet1
virtualNetworkPeeringName: peer
The peerCompleteVnets property set to false activates subnet filtering. The localSubnetNames and remoteSubnetNames properties specify which subnets can communicate across the peering. The enableOnlyIPv6Peering property controls whether only IPv6 address space is peered; set to false for dual-stack or IPv4-only scenarios.
Synchronize address space changes automatically
Virtual networks evolve as teams add or modify address ranges. The sync property ensures peerings automatically reflect these changes.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const virtualNetworkPeering = new azure_native.network.VirtualNetworkPeering("virtualNetworkPeering", {
allowForwardedTraffic: true,
allowGatewayTransit: false,
allowVirtualNetworkAccess: true,
remoteVirtualNetwork: {
id: "/subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2",
},
resourceGroupName: "peerTest",
syncRemoteAddressSpace: "true",
useRemoteGateways: false,
virtualNetworkName: "vnet1",
virtualNetworkPeeringName: "peer",
});
import pulumi
import pulumi_azure_native as azure_native
virtual_network_peering = azure_native.network.VirtualNetworkPeering("virtualNetworkPeering",
allow_forwarded_traffic=True,
allow_gateway_transit=False,
allow_virtual_network_access=True,
remote_virtual_network={
"id": "/subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2",
},
resource_group_name="peerTest",
sync_remote_address_space="true",
use_remote_gateways=False,
virtual_network_name="vnet1",
virtual_network_peering_name="peer")
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.NewVirtualNetworkPeering(ctx, "virtualNetworkPeering", &network.VirtualNetworkPeeringArgs{
AllowForwardedTraffic: pulumi.Bool(true),
AllowGatewayTransit: pulumi.Bool(false),
AllowVirtualNetworkAccess: pulumi.Bool(true),
RemoteVirtualNetwork: &network.SubResourceArgs{
Id: pulumi.String("/subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2"),
},
ResourceGroupName: pulumi.String("peerTest"),
SyncRemoteAddressSpace: pulumi.String("true"),
UseRemoteGateways: pulumi.Bool(false),
VirtualNetworkName: pulumi.String("vnet1"),
VirtualNetworkPeeringName: pulumi.String("peer"),
})
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 virtualNetworkPeering = new AzureNative.Network.VirtualNetworkPeering("virtualNetworkPeering", new()
{
AllowForwardedTraffic = true,
AllowGatewayTransit = false,
AllowVirtualNetworkAccess = true,
RemoteVirtualNetwork = new AzureNative.Network.Inputs.SubResourceArgs
{
Id = "/subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2",
},
ResourceGroupName = "peerTest",
SyncRemoteAddressSpace = "true",
UseRemoteGateways = false,
VirtualNetworkName = "vnet1",
VirtualNetworkPeeringName = "peer",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.network.VirtualNetworkPeering;
import com.pulumi.azurenative.network.VirtualNetworkPeeringArgs;
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 virtualNetworkPeering = new VirtualNetworkPeering("virtualNetworkPeering", VirtualNetworkPeeringArgs.builder()
.allowForwardedTraffic(true)
.allowGatewayTransit(false)
.allowVirtualNetworkAccess(true)
.remoteVirtualNetwork(SubResourceArgs.builder()
.id("/subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2")
.build())
.resourceGroupName("peerTest")
.syncRemoteAddressSpace("true")
.useRemoteGateways(false)
.virtualNetworkName("vnet1")
.virtualNetworkPeeringName("peer")
.build());
}
}
resources:
virtualNetworkPeering:
type: azure-native:network:VirtualNetworkPeering
properties:
allowForwardedTraffic: true
allowGatewayTransit: false
allowVirtualNetworkAccess: true
remoteVirtualNetwork:
id: /subscriptions/subid/resourceGroups/peerTest/providers/Microsoft.Network/virtualNetworks/vnet2
resourceGroupName: peerTest
syncRemoteAddressSpace: 'true'
useRemoteGateways: false
virtualNetworkName: vnet1
virtualNetworkPeeringName: peer
The syncRemoteAddressSpace property set to “true” triggers automatic synchronization when the remote VNet’s address space changes. Without this property, you must manually update the peering configuration when address ranges are added or removed.
Beyond these examples
These snippets focus on specific peering features: full VNet and subnet-level peering, gateway transit and forwarded traffic, and address space synchronization. They’re intentionally minimal rather than complete network architectures.
The examples reference pre-existing infrastructure such as both local and remote virtual networks, subnets within those VNets for subnet peering, and VPN or ExpressRoute gateways for gateway transit scenarios. They focus on configuring the peering rather than provisioning the underlying networks.
To keep things focused, common peering patterns are omitted, including:
- Reciprocal peering creation (peerings are unidirectional)
- IPv6-only peering (enableOnlyIPv6Peering)
- Gateway verification controls (doNotVerifyRemoteGateways)
- BGP community configuration (remoteBgpCommunities)
These omissions are intentional: the goal is to illustrate how each peering feature is wired, not provide drop-in networking modules. See the VirtualNetworkPeering resource reference for all available configuration options.
Let's configure Azure Virtual Network Peering
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Gateway Configuration
useRemoteGateways to true if your local virtual network already has a gateway configured. Remove the local gateway first or use it instead of the remote gateway.useRemoteGateways set to true at a time.allowGatewayTransit allows the remote VNet to use your gateway for transit, while useRemoteGateways allows your VNet to use the remote VNet’s gateway. Both must be configured correctly for gateway transit to work: set allowGatewayTransit to true on the VNet with the gateway, and useRemoteGateways to true on the VNet without one.Peering Scope & Subnets
peerCompleteVnets to true to peer entire virtual network address spaces, or false to peer only specific subnets. When false, specify which subnets to peer using localSubnetNames and remoteSubnetNames.peerCompleteVnets to false and specify the subnet names in localSubnetNames and remoteSubnetNames arrays.enableOnlyIPv6Peering to true, peerCompleteVnets to false, and specify the subnets using localSubnetNames and remoteSubnetNames.Traffic & Access Control
Three flags control traffic behavior:
allowVirtualNetworkAccessenables VMs in the local VNet to access VMs in the remote VNetallowForwardedTrafficallows forwarded traffic from local VMs to pass to the remote VNetallowGatewayTransitallows the remote VNet to use your VNet’s gateway for transit
Address Space Management
syncRemoteAddressSpace to “true” to sync the peering with the current address space on the remote VNet after it’s updated.resourceGroupName, virtualNetworkName, and virtualNetworkPeeringName properties are immutable after creation. To change these, you must delete and recreate the peering.