Configure Azure Firewall Policy Rule Collection Groups

The azure-native:network:FirewallPolicyRuleCollectionGroup resource, part of the Pulumi Azure Native provider, organizes firewall rules into prioritized collections within an Azure Firewall Policy. This guide focuses on four capabilities: DNAT rules for inbound translation, network and application filtering, IP Groups and web category filtering, and HTTP header injection.

Rule collection groups belong to a Firewall Policy and may reference IP Groups or other Azure resources. The examples are intentionally small. Combine them with your own Firewall Policy, IP Groups, and network architecture.

Translate external traffic to internal destinations

Organizations exposing internal services use DNAT rules to translate public addresses and ports to private backend targets.

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

const firewallPolicyRuleCollectionGroup = new azure_native.network.FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup", {
    firewallPolicyName: "firewallPolicy",
    priority: 100,
    resourceGroupName: "rg1",
    ruleCollectionGroupName: "ruleCollectionGroup1",
    ruleCollections: [{
        action: {
            type: azure_native.network.FirewallPolicyNatRuleCollectionActionType.DNAT,
        },
        name: "Example-Nat-Rule-Collection",
        priority: 100,
        ruleCollectionType: "FirewallPolicyNatRuleCollection",
        rules: [{
            destinationAddresses: ["152.23.32.23"],
            destinationPorts: ["8080"],
            ipProtocols: [
                azure_native.network.FirewallPolicyRuleNetworkProtocol.TCP,
                azure_native.network.FirewallPolicyRuleNetworkProtocol.UDP,
            ],
            name: "nat-rule1",
            ruleType: "NatRule",
            sourceAddresses: ["2.2.2.2"],
            sourceIpGroups: [],
            translatedFqdn: "internalhttp.server.net",
            translatedPort: "8080",
        }],
    }],
});
import pulumi
import pulumi_azure_native as azure_native

firewall_policy_rule_collection_group = azure_native.network.FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup",
    firewall_policy_name="firewallPolicy",
    priority=100,
    resource_group_name="rg1",
    rule_collection_group_name="ruleCollectionGroup1",
    rule_collections=[{
        "action": {
            "type": azure_native.network.FirewallPolicyNatRuleCollectionActionType.DNAT,
        },
        "name": "Example-Nat-Rule-Collection",
        "priority": 100,
        "rule_collection_type": "FirewallPolicyNatRuleCollection",
        "rules": [{
            "destination_addresses": ["152.23.32.23"],
            "destination_ports": ["8080"],
            "ip_protocols": [
                azure_native.network.FirewallPolicyRuleNetworkProtocol.TCP,
                azure_native.network.FirewallPolicyRuleNetworkProtocol.UDP,
            ],
            "name": "nat-rule1",
            "rule_type": "NatRule",
            "source_addresses": ["2.2.2.2"],
            "source_ip_groups": [],
            "translated_fqdn": "internalhttp.server.net",
            "translated_port": "8080",
        }],
    }])
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.NewFirewallPolicyRuleCollectionGroup(ctx, "firewallPolicyRuleCollectionGroup", &network.FirewallPolicyRuleCollectionGroupArgs{
			FirewallPolicyName:      pulumi.String("firewallPolicy"),
			Priority:                pulumi.Int(100),
			ResourceGroupName:       pulumi.String("rg1"),
			RuleCollectionGroupName: pulumi.String("ruleCollectionGroup1"),
			RuleCollections: pulumi.Array{
				network.FirewallPolicyNatRuleCollection{
					Action: network.FirewallPolicyNatRuleCollectionAction{
						Type: network.FirewallPolicyNatRuleCollectionActionTypeDNAT,
					},
					Name:               "Example-Nat-Rule-Collection",
					Priority:           100,
					RuleCollectionType: "FirewallPolicyNatRuleCollection",
					Rules: []interface{}{
						network.NatRuleType{
							DestinationAddresses: []string{
								"152.23.32.23",
							},
							DestinationPorts: []string{
								"8080",
							},
							IpProtocols: []network.FirewallPolicyRuleNetworkProtocol{
								network.FirewallPolicyRuleNetworkProtocolTCP,
								network.FirewallPolicyRuleNetworkProtocolUDP,
							},
							Name:     "nat-rule1",
							RuleType: "NatRule",
							SourceAddresses: []string{
								"2.2.2.2",
							},
							SourceIpGroups: []interface{}{},
							TranslatedFqdn: "internalhttp.server.net",
							TranslatedPort: "8080",
						},
					},
				},
			},
		})
		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 firewallPolicyRuleCollectionGroup = new AzureNative.Network.FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup", new()
    {
        FirewallPolicyName = "firewallPolicy",
        Priority = 100,
        ResourceGroupName = "rg1",
        RuleCollectionGroupName = "ruleCollectionGroup1",
        RuleCollections = new[]
        {
            new AzureNative.Network.Inputs.FirewallPolicyNatRuleCollectionArgs
            {
                Action = new AzureNative.Network.Inputs.FirewallPolicyNatRuleCollectionActionArgs
                {
                    Type = AzureNative.Network.FirewallPolicyNatRuleCollectionActionType.DNAT,
                },
                Name = "Example-Nat-Rule-Collection",
                Priority = 100,
                RuleCollectionType = "FirewallPolicyNatRuleCollection",
                Rules = new[]
                {
                    new AzureNative.Network.Inputs.NatRuleArgs
                    {
                        DestinationAddresses = new[]
                        {
                            "152.23.32.23",
                        },
                        DestinationPorts = new[]
                        {
                            "8080",
                        },
                        IpProtocols = new[]
                        {
                            AzureNative.Network.FirewallPolicyRuleNetworkProtocol.TCP,
                            AzureNative.Network.FirewallPolicyRuleNetworkProtocol.UDP,
                        },
                        Name = "nat-rule1",
                        RuleType = "NatRule",
                        SourceAddresses = new[]
                        {
                            "2.2.2.2",
                        },
                        SourceIpGroups = new() { },
                        TranslatedFqdn = "internalhttp.server.net",
                        TranslatedPort = "8080",
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.network.FirewallPolicyRuleCollectionGroup;
import com.pulumi.azurenative.network.FirewallPolicyRuleCollectionGroupArgs;
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 firewallPolicyRuleCollectionGroup = new FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup", FirewallPolicyRuleCollectionGroupArgs.builder()
            .firewallPolicyName("firewallPolicy")
            .priority(100)
            .resourceGroupName("rg1")
            .ruleCollectionGroupName("ruleCollectionGroup1")
            .ruleCollections(FirewallPolicyNatRuleCollectionArgs.builder()
                .action(FirewallPolicyNatRuleCollectionActionArgs.builder()
                    .type("DNAT")
                    .build())
                .name("Example-Nat-Rule-Collection")
                .priority(100)
                .ruleCollectionType("FirewallPolicyNatRuleCollection")
                .rules(%!v(PANIC=Format method: interface conversion: model.Expression is *model.FunctionCallExpression, not *model.ObjectConsExpression))
                .build())
            .build());

    }
}
resources:
  firewallPolicyRuleCollectionGroup:
    type: azure-native:network:FirewallPolicyRuleCollectionGroup
    properties:
      firewallPolicyName: firewallPolicy
      priority: 100
      resourceGroupName: rg1
      ruleCollectionGroupName: ruleCollectionGroup1
      ruleCollections:
        - action:
            type: DNAT
          name: Example-Nat-Rule-Collection
          priority: 100
          ruleCollectionType: FirewallPolicyNatRuleCollection
          rules:
            - destinationAddresses:
                - 152.23.32.23
              destinationPorts:
                - '8080'
              ipProtocols:
                - TCP
                - UDP
              name: nat-rule1
              ruleType: NatRule
              sourceAddresses:
                - 2.2.2.2
              sourceIpGroups: []
              translatedFqdn: internalhttp.server.net
              translatedPort: '8080'

When traffic arrives at the firewall’s public IP (destinationAddresses) on port 8080, the DNAT action translates it to the internal FQDN (translatedFqdn) and port (translatedPort). The ipProtocols property specifies which protocols trigger the translation. This enables external clients to reach internal services without exposing private addresses.

Block traffic with network filtering rules

Network administrators create deny rules to prevent specific source networks from reaching destinations.

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

const firewallPolicyRuleCollectionGroup = new azure_native.network.FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup", {
    firewallPolicyName: "firewallPolicy",
    priority: 100,
    resourceGroupName: "rg1",
    ruleCollectionGroupName: "ruleCollectionGroup1",
    ruleCollections: [{
        action: {
            type: azure_native.network.FirewallPolicyFilterRuleCollectionActionType.Deny,
        },
        name: "Example-Filter-Rule-Collection",
        priority: 100,
        ruleCollectionType: "FirewallPolicyFilterRuleCollection",
        rules: [{
            destinationAddresses: ["*"],
            destinationPorts: ["*"],
            ipProtocols: [azure_native.network.FirewallPolicyRuleNetworkProtocol.TCP],
            name: "network-rule1",
            ruleType: "NetworkRule",
            sourceAddresses: ["10.1.25.0/24"],
        }],
    }],
});
import pulumi
import pulumi_azure_native as azure_native

firewall_policy_rule_collection_group = azure_native.network.FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup",
    firewall_policy_name="firewallPolicy",
    priority=100,
    resource_group_name="rg1",
    rule_collection_group_name="ruleCollectionGroup1",
    rule_collections=[{
        "action": {
            "type": azure_native.network.FirewallPolicyFilterRuleCollectionActionType.DENY,
        },
        "name": "Example-Filter-Rule-Collection",
        "priority": 100,
        "rule_collection_type": "FirewallPolicyFilterRuleCollection",
        "rules": [{
            "destination_addresses": ["*"],
            "destination_ports": ["*"],
            "ip_protocols": [azure_native.network.FirewallPolicyRuleNetworkProtocol.TCP],
            "name": "network-rule1",
            "rule_type": "NetworkRule",
            "source_addresses": ["10.1.25.0/24"],
        }],
    }])
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.NewFirewallPolicyRuleCollectionGroup(ctx, "firewallPolicyRuleCollectionGroup", &network.FirewallPolicyRuleCollectionGroupArgs{
			FirewallPolicyName:      pulumi.String("firewallPolicy"),
			Priority:                pulumi.Int(100),
			ResourceGroupName:       pulumi.String("rg1"),
			RuleCollectionGroupName: pulumi.String("ruleCollectionGroup1"),
			RuleCollections: pulumi.Array{
				network.FirewallPolicyFilterRuleCollection{
					Action: network.FirewallPolicyFilterRuleCollectionAction{
						Type: network.FirewallPolicyFilterRuleCollectionActionTypeDeny,
					},
					Name:               "Example-Filter-Rule-Collection",
					Priority:           100,
					RuleCollectionType: "FirewallPolicyFilterRuleCollection",
					Rules: []interface{}{
						network.NetworkRule{
							DestinationAddresses: []string{
								"*",
							},
							DestinationPorts: []string{
								"*",
							},
							IpProtocols: []network.FirewallPolicyRuleNetworkProtocol{
								network.FirewallPolicyRuleNetworkProtocolTCP,
							},
							Name:     "network-rule1",
							RuleType: "NetworkRule",
							SourceAddresses: []string{
								"10.1.25.0/24",
							},
						},
					},
				},
			},
		})
		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 firewallPolicyRuleCollectionGroup = new AzureNative.Network.FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup", new()
    {
        FirewallPolicyName = "firewallPolicy",
        Priority = 100,
        ResourceGroupName = "rg1",
        RuleCollectionGroupName = "ruleCollectionGroup1",
        RuleCollections = new[]
        {
            new AzureNative.Network.Inputs.FirewallPolicyFilterRuleCollectionArgs
            {
                Action = new AzureNative.Network.Inputs.FirewallPolicyFilterRuleCollectionActionArgs
                {
                    Type = AzureNative.Network.FirewallPolicyFilterRuleCollectionActionType.Deny,
                },
                Name = "Example-Filter-Rule-Collection",
                Priority = 100,
                RuleCollectionType = "FirewallPolicyFilterRuleCollection",
                Rules = new[]
                {
                    new AzureNative.Network.Inputs.NetworkRuleArgs
                    {
                        DestinationAddresses = new[]
                        {
                            "*",
                        },
                        DestinationPorts = new[]
                        {
                            "*",
                        },
                        IpProtocols = new[]
                        {
                            AzureNative.Network.FirewallPolicyRuleNetworkProtocol.TCP,
                        },
                        Name = "network-rule1",
                        RuleType = "NetworkRule",
                        SourceAddresses = new[]
                        {
                            "10.1.25.0/24",
                        },
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.network.FirewallPolicyRuleCollectionGroup;
import com.pulumi.azurenative.network.FirewallPolicyRuleCollectionGroupArgs;
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 firewallPolicyRuleCollectionGroup = new FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup", FirewallPolicyRuleCollectionGroupArgs.builder()
            .firewallPolicyName("firewallPolicy")
            .priority(100)
            .resourceGroupName("rg1")
            .ruleCollectionGroupName("ruleCollectionGroup1")
            .ruleCollections(FirewallPolicyFilterRuleCollectionArgs.builder()
                .action(FirewallPolicyFilterRuleCollectionActionArgs.builder()
                    .type("Deny")
                    .build())
                .name("Example-Filter-Rule-Collection")
                .priority(100)
                .ruleCollectionType("FirewallPolicyFilterRuleCollection")
                .rules(%!v(PANIC=Format method: interface conversion: model.Expression is *model.FunctionCallExpression, not *model.ObjectConsExpression))
                .build())
            .build());

    }
}
resources:
  firewallPolicyRuleCollectionGroup:
    type: azure-native:network:FirewallPolicyRuleCollectionGroup
    properties:
      firewallPolicyName: firewallPolicy
      priority: 100
      resourceGroupName: rg1
      ruleCollectionGroupName: ruleCollectionGroup1
      ruleCollections:
        - action:
            type: Deny
          name: Example-Filter-Rule-Collection
          priority: 100
          ruleCollectionType: FirewallPolicyFilterRuleCollection
          rules:
            - destinationAddresses:
                - '*'
              destinationPorts:
                - '*'
              ipProtocols:
                - TCP
              name: network-rule1
              ruleType: NetworkRule
              sourceAddresses:
                - 10.1.25.0/24

The FirewallPolicyFilterRuleCollection with a Deny action blocks matching traffic. The NetworkRule type filters by IP addresses and protocols rather than application-layer attributes. Here, all TCP traffic from 10.1.25.0/24 is denied regardless of destination, implementing network segmentation.

Reference IP Groups for scalable address management

Large deployments manage IP addresses centrally through IP Groups, allowing rules to reference collections rather than individual addresses.

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

const firewallPolicyRuleCollectionGroup = new azure_native.network.FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup", {
    firewallPolicyName: "firewallPolicy",
    priority: 110,
    resourceGroupName: "rg1",
    ruleCollectionGroupName: "ruleCollectionGroup1",
    ruleCollections: [{
        action: {
            type: azure_native.network.FirewallPolicyFilterRuleCollectionActionType.Deny,
        },
        name: "Example-Filter-Rule-Collection",
        ruleCollectionType: "FirewallPolicyFilterRuleCollection",
        rules: [{
            destinationIpGroups: ["/subscriptions/subid/providers/Microsoft.Network/resourceGroup/rg1/ipGroups/ipGroups2"],
            destinationPorts: ["*"],
            ipProtocols: [azure_native.network.FirewallPolicyRuleNetworkProtocol.TCP],
            name: "network-1",
            ruleType: "NetworkRule",
            sourceIpGroups: ["/subscriptions/subid/providers/Microsoft.Network/resourceGroup/rg1/ipGroups/ipGroups1"],
        }],
    }],
});
import pulumi
import pulumi_azure_native as azure_native

firewall_policy_rule_collection_group = azure_native.network.FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup",
    firewall_policy_name="firewallPolicy",
    priority=110,
    resource_group_name="rg1",
    rule_collection_group_name="ruleCollectionGroup1",
    rule_collections=[{
        "action": {
            "type": azure_native.network.FirewallPolicyFilterRuleCollectionActionType.DENY,
        },
        "name": "Example-Filter-Rule-Collection",
        "rule_collection_type": "FirewallPolicyFilterRuleCollection",
        "rules": [{
            "destination_ip_groups": ["/subscriptions/subid/providers/Microsoft.Network/resourceGroup/rg1/ipGroups/ipGroups2"],
            "destination_ports": ["*"],
            "ip_protocols": [azure_native.network.FirewallPolicyRuleNetworkProtocol.TCP],
            "name": "network-1",
            "rule_type": "NetworkRule",
            "source_ip_groups": ["/subscriptions/subid/providers/Microsoft.Network/resourceGroup/rg1/ipGroups/ipGroups1"],
        }],
    }])
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.NewFirewallPolicyRuleCollectionGroup(ctx, "firewallPolicyRuleCollectionGroup", &network.FirewallPolicyRuleCollectionGroupArgs{
			FirewallPolicyName:      pulumi.String("firewallPolicy"),
			Priority:                pulumi.Int(110),
			ResourceGroupName:       pulumi.String("rg1"),
			RuleCollectionGroupName: pulumi.String("ruleCollectionGroup1"),
			RuleCollections: pulumi.Array{
				network.FirewallPolicyFilterRuleCollection{
					Action: network.FirewallPolicyFilterRuleCollectionAction{
						Type: network.FirewallPolicyFilterRuleCollectionActionTypeDeny,
					},
					Name:               "Example-Filter-Rule-Collection",
					RuleCollectionType: "FirewallPolicyFilterRuleCollection",
					Rules: []interface{}{
						network.NetworkRule{
							DestinationIpGroups: []string{
								"/subscriptions/subid/providers/Microsoft.Network/resourceGroup/rg1/ipGroups/ipGroups2",
							},
							DestinationPorts: []string{
								"*",
							},
							IpProtocols: []network.FirewallPolicyRuleNetworkProtocol{
								network.FirewallPolicyRuleNetworkProtocolTCP,
							},
							Name:     "network-1",
							RuleType: "NetworkRule",
							SourceIpGroups: []string{
								"/subscriptions/subid/providers/Microsoft.Network/resourceGroup/rg1/ipGroups/ipGroups1",
							},
						},
					},
				},
			},
		})
		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 firewallPolicyRuleCollectionGroup = new AzureNative.Network.FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup", new()
    {
        FirewallPolicyName = "firewallPolicy",
        Priority = 110,
        ResourceGroupName = "rg1",
        RuleCollectionGroupName = "ruleCollectionGroup1",
        RuleCollections = new[]
        {
            new AzureNative.Network.Inputs.FirewallPolicyFilterRuleCollectionArgs
            {
                Action = new AzureNative.Network.Inputs.FirewallPolicyFilterRuleCollectionActionArgs
                {
                    Type = AzureNative.Network.FirewallPolicyFilterRuleCollectionActionType.Deny,
                },
                Name = "Example-Filter-Rule-Collection",
                RuleCollectionType = "FirewallPolicyFilterRuleCollection",
                Rules = new[]
                {
                    new AzureNative.Network.Inputs.NetworkRuleArgs
                    {
                        DestinationIpGroups = new[]
                        {
                            "/subscriptions/subid/providers/Microsoft.Network/resourceGroup/rg1/ipGroups/ipGroups2",
                        },
                        DestinationPorts = new[]
                        {
                            "*",
                        },
                        IpProtocols = new[]
                        {
                            AzureNative.Network.FirewallPolicyRuleNetworkProtocol.TCP,
                        },
                        Name = "network-1",
                        RuleType = "NetworkRule",
                        SourceIpGroups = new[]
                        {
                            "/subscriptions/subid/providers/Microsoft.Network/resourceGroup/rg1/ipGroups/ipGroups1",
                        },
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.network.FirewallPolicyRuleCollectionGroup;
import com.pulumi.azurenative.network.FirewallPolicyRuleCollectionGroupArgs;
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 firewallPolicyRuleCollectionGroup = new FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup", FirewallPolicyRuleCollectionGroupArgs.builder()
            .firewallPolicyName("firewallPolicy")
            .priority(110)
            .resourceGroupName("rg1")
            .ruleCollectionGroupName("ruleCollectionGroup1")
            .ruleCollections(FirewallPolicyFilterRuleCollectionArgs.builder()
                .action(FirewallPolicyFilterRuleCollectionActionArgs.builder()
                    .type("Deny")
                    .build())
                .name("Example-Filter-Rule-Collection")
                .ruleCollectionType("FirewallPolicyFilterRuleCollection")
                .rules(%!v(PANIC=Format method: interface conversion: model.Expression is *model.FunctionCallExpression, not *model.ObjectConsExpression))
                .build())
            .build());

    }
}
resources:
  firewallPolicyRuleCollectionGroup:
    type: azure-native:network:FirewallPolicyRuleCollectionGroup
    properties:
      firewallPolicyName: firewallPolicy
      priority: 110
      resourceGroupName: rg1
      ruleCollectionGroupName: ruleCollectionGroup1
      ruleCollections:
        - action:
            type: Deny
          name: Example-Filter-Rule-Collection
          ruleCollectionType: FirewallPolicyFilterRuleCollection
          rules:
            - destinationIpGroups:
                - /subscriptions/subid/providers/Microsoft.Network/resourceGroup/rg1/ipGroups/ipGroups2
              destinationPorts:
                - '*'
              ipProtocols:
                - TCP
              name: network-1
              ruleType: NetworkRule
              sourceIpGroups:
                - /subscriptions/subid/providers/Microsoft.Network/resourceGroup/rg1/ipGroups/ipGroups1

Instead of listing individual addresses, sourceIpGroups and destinationIpGroups reference IP Group resources by their Azure resource IDs. When you update an IP Group, all rules referencing it automatically use the new addresses without rule modifications.

Block traffic by web content category

Security teams use web categories to block entire classes of sites without maintaining URL lists.

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

const firewallPolicyRuleCollectionGroup = new azure_native.network.FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup", {
    firewallPolicyName: "firewallPolicy",
    priority: 110,
    resourceGroupName: "rg1",
    ruleCollectionGroupName: "ruleCollectionGroup1",
    ruleCollections: [{
        action: {
            type: azure_native.network.FirewallPolicyFilterRuleCollectionActionType.Deny,
        },
        name: "Example-Filter-Rule-Collection",
        ruleCollectionType: "FirewallPolicyFilterRuleCollection",
        rules: [{
            description: "Deny inbound rule",
            name: "rule1",
            protocols: [{
                port: 443,
                protocolType: azure_native.network.FirewallPolicyRuleApplicationProtocolType.Https,
            }],
            ruleType: "ApplicationRule",
            sourceAddresses: [
                "216.58.216.164",
                "10.0.0.0/24",
            ],
            webCategories: ["Hacking"],
        }],
    }],
});
import pulumi
import pulumi_azure_native as azure_native

firewall_policy_rule_collection_group = azure_native.network.FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup",
    firewall_policy_name="firewallPolicy",
    priority=110,
    resource_group_name="rg1",
    rule_collection_group_name="ruleCollectionGroup1",
    rule_collections=[{
        "action": {
            "type": azure_native.network.FirewallPolicyFilterRuleCollectionActionType.DENY,
        },
        "name": "Example-Filter-Rule-Collection",
        "rule_collection_type": "FirewallPolicyFilterRuleCollection",
        "rules": [{
            "description": "Deny inbound rule",
            "name": "rule1",
            "protocols": [{
                "port": 443,
                "protocol_type": azure_native.network.FirewallPolicyRuleApplicationProtocolType.HTTPS,
            }],
            "rule_type": "ApplicationRule",
            "source_addresses": [
                "216.58.216.164",
                "10.0.0.0/24",
            ],
            "web_categories": ["Hacking"],
        }],
    }])
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.NewFirewallPolicyRuleCollectionGroup(ctx, "firewallPolicyRuleCollectionGroup", &network.FirewallPolicyRuleCollectionGroupArgs{
			FirewallPolicyName:      pulumi.String("firewallPolicy"),
			Priority:                pulumi.Int(110),
			ResourceGroupName:       pulumi.String("rg1"),
			RuleCollectionGroupName: pulumi.String("ruleCollectionGroup1"),
			RuleCollections: pulumi.Array{
				network.FirewallPolicyFilterRuleCollection{
					Action: network.FirewallPolicyFilterRuleCollectionAction{
						Type: network.FirewallPolicyFilterRuleCollectionActionTypeDeny,
					},
					Name:               "Example-Filter-Rule-Collection",
					RuleCollectionType: "FirewallPolicyFilterRuleCollection",
					Rules: []interface{}{
						network.ApplicationRule{
							Description: "Deny inbound rule",
							Name:        "rule1",
							Protocols: []network.FirewallPolicyRuleApplicationProtocol{
								{
									Port:         443,
									ProtocolType: network.FirewallPolicyRuleApplicationProtocolTypeHttps,
								},
							},
							RuleType: "ApplicationRule",
							SourceAddresses: []string{
								"216.58.216.164",
								"10.0.0.0/24",
							},
							WebCategories: []string{
								"Hacking",
							},
						},
					},
				},
			},
		})
		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 firewallPolicyRuleCollectionGroup = new AzureNative.Network.FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup", new()
    {
        FirewallPolicyName = "firewallPolicy",
        Priority = 110,
        ResourceGroupName = "rg1",
        RuleCollectionGroupName = "ruleCollectionGroup1",
        RuleCollections = new[]
        {
            new AzureNative.Network.Inputs.FirewallPolicyFilterRuleCollectionArgs
            {
                Action = new AzureNative.Network.Inputs.FirewallPolicyFilterRuleCollectionActionArgs
                {
                    Type = AzureNative.Network.FirewallPolicyFilterRuleCollectionActionType.Deny,
                },
                Name = "Example-Filter-Rule-Collection",
                RuleCollectionType = "FirewallPolicyFilterRuleCollection",
                Rules = new[]
                {
                    new AzureNative.Network.Inputs.ApplicationRuleArgs
                    {
                        Description = "Deny inbound rule",
                        Name = "rule1",
                        Protocols = new[]
                        {
                            new AzureNative.Network.Inputs.FirewallPolicyRuleApplicationProtocolArgs
                            {
                                Port = 443,
                                ProtocolType = AzureNative.Network.FirewallPolicyRuleApplicationProtocolType.Https,
                            },
                        },
                        RuleType = "ApplicationRule",
                        SourceAddresses = new[]
                        {
                            "216.58.216.164",
                            "10.0.0.0/24",
                        },
                        WebCategories = new[]
                        {
                            "Hacking",
                        },
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.network.FirewallPolicyRuleCollectionGroup;
import com.pulumi.azurenative.network.FirewallPolicyRuleCollectionGroupArgs;
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 firewallPolicyRuleCollectionGroup = new FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup", FirewallPolicyRuleCollectionGroupArgs.builder()
            .firewallPolicyName("firewallPolicy")
            .priority(110)
            .resourceGroupName("rg1")
            .ruleCollectionGroupName("ruleCollectionGroup1")
            .ruleCollections(FirewallPolicyFilterRuleCollectionArgs.builder()
                .action(FirewallPolicyFilterRuleCollectionActionArgs.builder()
                    .type("Deny")
                    .build())
                .name("Example-Filter-Rule-Collection")
                .ruleCollectionType("FirewallPolicyFilterRuleCollection")
                .rules(%!v(PANIC=Format method: interface conversion: model.Expression is *model.FunctionCallExpression, not *model.ObjectConsExpression))
                .build())
            .build());

    }
}
resources:
  firewallPolicyRuleCollectionGroup:
    type: azure-native:network:FirewallPolicyRuleCollectionGroup
    properties:
      firewallPolicyName: firewallPolicy
      priority: 110
      resourceGroupName: rg1
      ruleCollectionGroupName: ruleCollectionGroup1
      ruleCollections:
        - action:
            type: Deny
          name: Example-Filter-Rule-Collection
          ruleCollectionType: FirewallPolicyFilterRuleCollection
          rules:
            - description: Deny inbound rule
              name: rule1
              protocols:
                - port: 443
                  protocolType: Https
              ruleType: ApplicationRule
              sourceAddresses:
                - 216.58.216.164
                - 10.0.0.0/24
              webCategories:
                - Hacking

The ApplicationRule type filters HTTPS traffic by webCategories, blocking access to sites Azure classifies as “Hacking” without specifying individual domains. The protocols property defines which application protocols to inspect. This provides broad protection against entire threat categories.

Insert HTTP headers for tenant restriction

Organizations implementing multi-tenant access controls inject HTTP headers to restrict which Azure AD tenants users can authenticate against.

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

const firewallPolicyRuleCollectionGroup = new azure_native.network.FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup", {
    firewallPolicyName: "firewallPolicy",
    priority: 110,
    resourceGroupName: "rg1",
    ruleCollectionGroupName: "ruleCollectionGroup1",
    ruleCollections: [{
        action: {
            type: azure_native.network.FirewallPolicyFilterRuleCollectionActionType.Allow,
        },
        name: "Example-Filter-Rule-Collection",
        ruleCollectionType: "FirewallPolicyFilterRuleCollection",
        rules: [{
            description: "Insert trusted tenants header",
            fqdnTags: ["WindowsVirtualDesktop"],
            httpHeadersToInsert: [{
                headerName: "Restrict-Access-To-Tenants",
                headerValue: "contoso.com,fabrikam.onmicrosoft.com",
            }],
            name: "rule1",
            protocols: [{
                port: 80,
                protocolType: azure_native.network.FirewallPolicyRuleApplicationProtocolType.Http,
            }],
            ruleType: "ApplicationRule",
            sourceAddresses: [
                "216.58.216.164",
                "10.0.0.0/24",
            ],
        }],
    }],
});
import pulumi
import pulumi_azure_native as azure_native

firewall_policy_rule_collection_group = azure_native.network.FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup",
    firewall_policy_name="firewallPolicy",
    priority=110,
    resource_group_name="rg1",
    rule_collection_group_name="ruleCollectionGroup1",
    rule_collections=[{
        "action": {
            "type": azure_native.network.FirewallPolicyFilterRuleCollectionActionType.ALLOW,
        },
        "name": "Example-Filter-Rule-Collection",
        "rule_collection_type": "FirewallPolicyFilterRuleCollection",
        "rules": [{
            "description": "Insert trusted tenants header",
            "fqdn_tags": ["WindowsVirtualDesktop"],
            "http_headers_to_insert": [{
                "header_name": "Restrict-Access-To-Tenants",
                "header_value": "contoso.com,fabrikam.onmicrosoft.com",
            }],
            "name": "rule1",
            "protocols": [{
                "port": 80,
                "protocol_type": azure_native.network.FirewallPolicyRuleApplicationProtocolType.HTTP,
            }],
            "rule_type": "ApplicationRule",
            "source_addresses": [
                "216.58.216.164",
                "10.0.0.0/24",
            ],
        }],
    }])
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.NewFirewallPolicyRuleCollectionGroup(ctx, "firewallPolicyRuleCollectionGroup", &network.FirewallPolicyRuleCollectionGroupArgs{
			FirewallPolicyName:      pulumi.String("firewallPolicy"),
			Priority:                pulumi.Int(110),
			ResourceGroupName:       pulumi.String("rg1"),
			RuleCollectionGroupName: pulumi.String("ruleCollectionGroup1"),
			RuleCollections: pulumi.Array{
				network.FirewallPolicyFilterRuleCollection{
					Action: network.FirewallPolicyFilterRuleCollectionAction{
						Type: network.FirewallPolicyFilterRuleCollectionActionTypeAllow,
					},
					Name:               "Example-Filter-Rule-Collection",
					RuleCollectionType: "FirewallPolicyFilterRuleCollection",
					Rules: []interface{}{
						network.ApplicationRule{
							Description: "Insert trusted tenants header",
							FqdnTags: []string{
								"WindowsVirtualDesktop",
							},
							HttpHeadersToInsert: []network.FirewallPolicyHttpHeaderToInsert{
								{
									HeaderName:  "Restrict-Access-To-Tenants",
									HeaderValue: "contoso.com,fabrikam.onmicrosoft.com",
								},
							},
							Name: "rule1",
							Protocols: []network.FirewallPolicyRuleApplicationProtocol{
								{
									Port:         80,
									ProtocolType: network.FirewallPolicyRuleApplicationProtocolTypeHttp,
								},
							},
							RuleType: "ApplicationRule",
							SourceAddresses: []string{
								"216.58.216.164",
								"10.0.0.0/24",
							},
						},
					},
				},
			},
		})
		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 firewallPolicyRuleCollectionGroup = new AzureNative.Network.FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup", new()
    {
        FirewallPolicyName = "firewallPolicy",
        Priority = 110,
        ResourceGroupName = "rg1",
        RuleCollectionGroupName = "ruleCollectionGroup1",
        RuleCollections = new[]
        {
            new AzureNative.Network.Inputs.FirewallPolicyFilterRuleCollectionArgs
            {
                Action = new AzureNative.Network.Inputs.FirewallPolicyFilterRuleCollectionActionArgs
                {
                    Type = AzureNative.Network.FirewallPolicyFilterRuleCollectionActionType.Allow,
                },
                Name = "Example-Filter-Rule-Collection",
                RuleCollectionType = "FirewallPolicyFilterRuleCollection",
                Rules = new[]
                {
                    new AzureNative.Network.Inputs.ApplicationRuleArgs
                    {
                        Description = "Insert trusted tenants header",
                        FqdnTags = new[]
                        {
                            "WindowsVirtualDesktop",
                        },
                        HttpHeadersToInsert = new[]
                        {
                            new AzureNative.Network.Inputs.FirewallPolicyHttpHeaderToInsertArgs
                            {
                                HeaderName = "Restrict-Access-To-Tenants",
                                HeaderValue = "contoso.com,fabrikam.onmicrosoft.com",
                            },
                        },
                        Name = "rule1",
                        Protocols = new[]
                        {
                            new AzureNative.Network.Inputs.FirewallPolicyRuleApplicationProtocolArgs
                            {
                                Port = 80,
                                ProtocolType = AzureNative.Network.FirewallPolicyRuleApplicationProtocolType.Http,
                            },
                        },
                        RuleType = "ApplicationRule",
                        SourceAddresses = new[]
                        {
                            "216.58.216.164",
                            "10.0.0.0/24",
                        },
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.network.FirewallPolicyRuleCollectionGroup;
import com.pulumi.azurenative.network.FirewallPolicyRuleCollectionGroupArgs;
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 firewallPolicyRuleCollectionGroup = new FirewallPolicyRuleCollectionGroup("firewallPolicyRuleCollectionGroup", FirewallPolicyRuleCollectionGroupArgs.builder()
            .firewallPolicyName("firewallPolicy")
            .priority(110)
            .resourceGroupName("rg1")
            .ruleCollectionGroupName("ruleCollectionGroup1")
            .ruleCollections(FirewallPolicyFilterRuleCollectionArgs.builder()
                .action(FirewallPolicyFilterRuleCollectionActionArgs.builder()
                    .type("Allow")
                    .build())
                .name("Example-Filter-Rule-Collection")
                .ruleCollectionType("FirewallPolicyFilterRuleCollection")
                .rules(%!v(PANIC=Format method: interface conversion: model.Expression is *model.FunctionCallExpression, not *model.ObjectConsExpression))
                .build())
            .build());

    }
}
resources:
  firewallPolicyRuleCollectionGroup:
    type: azure-native:network:FirewallPolicyRuleCollectionGroup
    properties:
      firewallPolicyName: firewallPolicy
      priority: 110
      resourceGroupName: rg1
      ruleCollectionGroupName: ruleCollectionGroup1
      ruleCollections:
        - action:
            type: Allow
          name: Example-Filter-Rule-Collection
          ruleCollectionType: FirewallPolicyFilterRuleCollection
          rules:
            - description: Insert trusted tenants header
              fqdnTags:
                - WindowsVirtualDesktop
              httpHeadersToInsert:
                - headerName: Restrict-Access-To-Tenants
                  headerValue: contoso.com,fabrikam.onmicrosoft.com
              name: rule1
              protocols:
                - port: 80
                  protocolType: Http
              ruleType: ApplicationRule
              sourceAddresses:
                - 216.58.216.164
                - 10.0.0.0/24

The httpHeadersToInsert property adds headers to matching HTTP traffic. Here, the Restrict-Access-To-Tenants header limits authentication to specified tenants (contoso.com, fabrikam.onmicrosoft.com). The fqdnTags property matches traffic to Windows Virtual Desktop services without listing individual FQDNs.

Beyond these examples

These snippets focus on specific rule collection group features: NAT, network, and application rule types, IP Groups and web category filtering, and HTTP header injection. They’re intentionally minimal rather than complete firewall configurations.

The examples reference pre-existing infrastructure such as Firewall Policy resources, IP Groups for relevant examples, and resource groups and subscriptions. They focus on rule collection configuration rather than provisioning the surrounding firewall infrastructure.

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

  • Rule priority ordering and conflict resolution
  • FQDN-based filtering (targetFqdns)
  • TLS inspection configuration
  • Threat intelligence integration

These omissions are intentional: the goal is to illustrate how each rule collection feature is wired, not provide drop-in firewall policies. See the FirewallPolicyRuleCollectionGroup resource reference for all available configuration options.

Let's configure Azure Firewall Policy Rule Collection Groups

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 rule collection group?
The firewallPolicyName, resourceGroupName, and ruleCollectionGroupName properties are immutable and cannot be modified after creation. Changing these requires recreating the resource.
How does priority work for rule collection groups?
Each rule collection group has a priority integer value that determines its evaluation order. Lower priority values are evaluated first. Examples show priorities like 100 and 110.
Rule Collections & Types
What's the difference between NAT and Filter rule collections?
NAT rule collections (FirewallPolicyNatRuleCollection) perform destination NAT with DNAT action, while Filter rule collections (FirewallPolicyFilterRuleCollection) allow or deny traffic. Specify the type using the ruleCollectionType property.
What action types are available for rule collections?
NAT collections support DNAT action, while Filter collections support Allow or Deny actions. Set the action using the action.type property.
What rule types can I use within collections?
NAT collections contain NatRule types, while Filter collections can contain NetworkRule or ApplicationRule types. Specify using the ruleType property within each rule.
Advanced Features
Can I use IP Groups instead of individual IP addresses?
Yes, use sourceIpGroups and destinationIpGroups properties with resource IDs pointing to IP Group resources (e.g., /subscriptions/subid/providers/Microsoft.Network/resourceGroup/rg1/ipGroups/ipGroups1).
How do I filter traffic by web category?
Use the webCategories property in ApplicationRule rules within a Filter collection. For example, set webCategories: ["Hacking"] to block hacking-related sites.
Can I insert custom HTTP headers into traffic?
Yes, use the httpHeadersToInsert property in ApplicationRule rules, specifying headerName and headerValue pairs (e.g., headerName: "Restrict-Access-To-Tenants").
Resource Properties
What does the size property represent?
The size output property is a read-only string showing the size of the rule collection group in MB (e.g., “1.2MB”).

Using a different cloud?

Explore networking guides for other cloud providers: