Configure Azure Firewall Policy Rule Collection Groups

The azure-native:network:FirewallPolicyRuleCollectionGroup resource, part of the Pulumi Azure Native provider, organizes firewall rules into collections within an Azure Firewall Policy. It controls evaluation order through priority values and groups related rules together. 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 infrastructure.

Translate inbound traffic with DNAT rules

Organizations exposing internal services through Azure Firewall use DNAT to map public IPs to private backend addresses, allowing external clients to reach internal resources.

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), the DNAT action translates it to the internal FQDN (translatedFqdn) and port (translatedPort). The rule matches based on sourceAddresses, destinationPorts, and ipProtocols. Priority determines evaluation order when multiple rule collections exist.

Block traffic with network filter rules

Network administrators create deny rules to block specific traffic patterns, providing a first line of defense before application rules evaluate.

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 Deny action drops matching traffic. Network rules evaluate based on sourceAddresses, destinationAddresses, destinationPorts, and ipProtocols. The wildcard (*) matches any destination or port. Rules within a collection are evaluated in order until a match occurs.

Reference IP Groups for centralized address management

Teams managing large address lists use IP Groups to centralize definitions and reference them across multiple rules, simplifying updates when ranges change.

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 resource IDs. When you update an IP Group, all rules referencing it automatically use the new addresses. This reduces duplication and maintenance overhead.

Block traffic by web category

Security teams use web categories to block entire classes of websites without maintaining explicit domain 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 webCategories property accepts predefined categories like “Hacking”, “Gambling”, or “Adult Content”. Azure Firewall maintains the underlying domain lists. Application rules also specify protocols (HTTP/HTTPS) and sourceAddresses. The Deny action blocks matching requests.

Insert HTTP headers for tenant restriction

Organizations implementing tenant restrictions inject HTTP headers into outbound requests to control 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 requests. Here, “Restrict-Access-To-Tenants” limits authentication to specified domains. The fqdnTags property uses predefined service tags like “WindowsVirtualDesktop” instead of explicit FQDNs. The Allow action permits traffic after header insertion.

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 for tenant control. They’re intentionally minimal rather than complete firewall policies.

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

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

  • Rule collection 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 modules. 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

Rule Types & Collections
What's the difference between NAT and Filter rule collections?
NAT collections use FirewallPolicyNatRuleCollection with DNAT action to translate destination addresses and ports. Filter collections use FirewallPolicyFilterRuleCollection with Allow or Deny actions to permit or block traffic.
What rule types can I use in my collections?
You can use three rule types: NatRule for destination NAT, NetworkRule for layer 3/4 filtering, and ApplicationRule for layer 7 filtering with FQDN or web category support.
Can I mix different rule types in one collection?
NAT collections can only contain NatRule types, while Filter collections can contain both NetworkRule and ApplicationRule types depending on your filtering needs.
Configuration & Priority
How is rule evaluation order determined?
Rule collection groups are evaluated based on their priority value, with lower numbers evaluated first. Within a collection, rules are evaluated in the order they appear.
What protocols are supported in network rules?
Network rules support TCP, UDP, ICMP, and Any protocols through the ipProtocols property.
Advanced Features
Can I use IP Groups instead of specifying individual IP addresses?
Yes, use sourceIpGroups and destinationIpGroups properties with full resource IDs (e.g., /subscriptions/subid/providers/Microsoft.Network/resourceGroup/rg1/ipGroups/ipGroups1) instead of sourceAddresses and destinationAddresses.
How do I filter traffic by web category?
In ApplicationRule types, use the webCategories property with category names like “Hacking” to block or allow traffic to specific website categories.
Can I insert custom HTTP headers into traffic?
Yes, use httpHeadersToInsert in ApplicationRule with headerName and headerValue properties. This is useful for scenarios like tenant restrictions (e.g., Restrict-Access-To-Tenants header).
Immutability & Limitations
What properties can't be changed after creation?
The firewallPolicyName, resourceGroupName, and ruleCollectionGroupName properties are immutable and require resource replacement if changed.

Using a different cloud?

Explore networking guides for other cloud providers: