The aws:networkfirewall/ruleGroup:RuleGroup resource, part of the Pulumi AWS provider, defines a Network Firewall rule group containing stateful or stateless traffic filtering rules. This guide focuses on three capabilities: domain and IP-based filtering, Suricata rule import and variables, and stateless inspection with custom actions.
Rule groups attach to Network Firewall policies, which are deployed to VPC endpoints. The examples are intentionally small. Combine them with your own firewall policies and VPC configuration.
Block access to specific domains
Network security teams often need to prevent traffic to known malicious or restricted domains. Network Firewall can inspect HTTP traffic and block requests based on domain names.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.networkfirewall.RuleGroup("example", {
capacity: 100,
name: "example",
type: "STATEFUL",
ruleGroup: {
rulesSource: {
rulesSourceList: {
generatedRulesType: "DENYLIST",
targetTypes: ["HTTP_HOST"],
targets: ["test.example.com"],
},
},
},
tags: {
Tag1: "Value1",
Tag2: "Value2",
},
});
import pulumi
import pulumi_aws as aws
example = aws.networkfirewall.RuleGroup("example",
capacity=100,
name="example",
type="STATEFUL",
rule_group={
"rules_source": {
"rules_source_list": {
"generated_rules_type": "DENYLIST",
"target_types": ["HTTP_HOST"],
"targets": ["test.example.com"],
},
},
},
tags={
"Tag1": "Value1",
"Tag2": "Value2",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/networkfirewall"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := networkfirewall.NewRuleGroup(ctx, "example", &networkfirewall.RuleGroupArgs{
Capacity: pulumi.Int(100),
Name: pulumi.String("example"),
Type: pulumi.String("STATEFUL"),
RuleGroup: &networkfirewall.RuleGroupRuleGroupArgs{
RulesSource: &networkfirewall.RuleGroupRuleGroupRulesSourceArgs{
RulesSourceList: &networkfirewall.RuleGroupRuleGroupRulesSourceRulesSourceListArgs{
GeneratedRulesType: pulumi.String("DENYLIST"),
TargetTypes: pulumi.StringArray{
pulumi.String("HTTP_HOST"),
},
Targets: pulumi.StringArray{
pulumi.String("test.example.com"),
},
},
},
},
Tags: pulumi.StringMap{
"Tag1": pulumi.String("Value1"),
"Tag2": pulumi.String("Value2"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.NetworkFirewall.RuleGroup("example", new()
{
Capacity = 100,
Name = "example",
Type = "STATEFUL",
RuleGroupConfiguration = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupArgs
{
RulesSource = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceArgs
{
RulesSourceList = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceRulesSourceListArgs
{
GeneratedRulesType = "DENYLIST",
TargetTypes = new[]
{
"HTTP_HOST",
},
Targets = new[]
{
"test.example.com",
},
},
},
},
Tags =
{
{ "Tag1", "Value1" },
{ "Tag2", "Value2" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.networkfirewall.RuleGroup;
import com.pulumi.aws.networkfirewall.RuleGroupArgs;
import com.pulumi.aws.networkfirewall.inputs.RuleGroupRuleGroupArgs;
import com.pulumi.aws.networkfirewall.inputs.RuleGroupRuleGroupRulesSourceArgs;
import com.pulumi.aws.networkfirewall.inputs.RuleGroupRuleGroupRulesSourceRulesSourceListArgs;
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 example = new RuleGroup("example", RuleGroupArgs.builder()
.capacity(100)
.name("example")
.type("STATEFUL")
.ruleGroup(RuleGroupRuleGroupArgs.builder()
.rulesSource(RuleGroupRuleGroupRulesSourceArgs.builder()
.rulesSourceList(RuleGroupRuleGroupRulesSourceRulesSourceListArgs.builder()
.generatedRulesType("DENYLIST")
.targetTypes("HTTP_HOST")
.targets("test.example.com")
.build())
.build())
.build())
.tags(Map.ofEntries(
Map.entry("Tag1", "Value1"),
Map.entry("Tag2", "Value2")
))
.build());
}
}
resources:
example:
type: aws:networkfirewall:RuleGroup
properties:
capacity: 100
name: example
type: STATEFUL
ruleGroup:
rulesSource:
rulesSourceList:
generatedRulesType: DENYLIST
targetTypes:
- HTTP_HOST
targets:
- test.example.com
tags:
Tag1: Value1
Tag2: Value2
The rulesSourceList property defines a simple domain-based filter. Set generatedRulesType to “DENYLIST” to block traffic, targetTypes to [“HTTP_HOST”] to inspect HTTP Host headers, and targets to the list of domains to block. The type property must be “STATEFUL” for domain inspection.
Allow traffic from specific source IPs
Applications that receive traffic from known partners or internal services need to permit connections from specific IP addresses while blocking others.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const ips = [
"1.1.1.1/32",
"1.0.0.1/32",
];
const example = new aws.networkfirewall.RuleGroup("example", {
capacity: 50,
description: "Permits http traffic from source",
name: "example",
type: "STATEFUL",
ruleGroup: {
rulesSource: {
statefulRules: ips.map((v, k) => ({key: k, value: v})).map(entry => ({
action: "PASS",
header: {
destination: "ANY",
destinationPort: "ANY",
protocol: "HTTP",
direction: "ANY",
sourcePort: "ANY",
source: entry.value,
},
ruleOptions: [{
keyword: "sid",
settings: ["1"],
}],
})),
},
},
tags: {
Name: "permit HTTP from source",
},
});
import pulumi
import pulumi_aws as aws
ips = [
"1.1.1.1/32",
"1.0.0.1/32",
]
example = aws.networkfirewall.RuleGroup("example",
capacity=50,
description="Permits http traffic from source",
name="example",
type="STATEFUL",
rule_group={
"rules_source": {
"stateful_rules": [{
"action": "PASS",
"header": {
"destination": "ANY",
"destination_port": "ANY",
"protocol": "HTTP",
"direction": "ANY",
"source_port": "ANY",
"source": entry["value"],
},
"rule_options": [{
"keyword": "sid",
"settings": ["1"],
}],
} for entry in [{"key": k, "value": v} for k, v in ips]],
},
},
tags={
"Name": "permit HTTP from source",
})
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var ips = new[]
{
"1.1.1.1/32",
"1.0.0.1/32",
};
var example = new Aws.NetworkFirewall.RuleGroup("example", new()
{
Capacity = 50,
Description = "Permits http traffic from source",
Name = "example",
Type = "STATEFUL",
RuleGroupConfiguration = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupArgs
{
RulesSource = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceArgs
{
StatefulRules = ips.Select((v, k) => new { Key = k, Value = v }).Select(entry =>
{
return new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceStatefulRuleArgs
{
Action = "PASS",
Header = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceStatefulRuleHeaderArgs
{
Destination = "ANY",
DestinationPort = "ANY",
Protocol = "HTTP",
Direction = "ANY",
SourcePort = "ANY",
Source = entry.Value,
},
RuleOptions = new[]
{
new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceStatefulRuleRuleOptionArgs
{
Keyword = "sid",
Settings = new[]
{
"1",
},
},
},
};
}).ToList(),
},
},
Tags =
{
{ "Name", "permit HTTP from source" },
},
});
});
Each statefulRule defines a 5-tuple match (source, destination, ports, protocol, direction) and an action. The header property specifies what traffic to match; the action property determines whether to PASS or DROP. The ruleOptions property includes a unique sid (signature ID) required by the Suricata rule format.
Import existing Suricata rules from a file
Teams migrating from other firewall solutions or using community rule sets often have existing Suricata-format rules they want to reuse.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as std from "@pulumi/std";
const example = new aws.networkfirewall.RuleGroup("example", {
capacity: 100,
name: "example",
type: "STATEFUL",
rules: std.file({
input: "example.rules",
}).then(invoke => invoke.result),
tags: {
Tag1: "Value1",
Tag2: "Value2",
},
});
import pulumi
import pulumi_aws as aws
import pulumi_std as std
example = aws.networkfirewall.RuleGroup("example",
capacity=100,
name="example",
type="STATEFUL",
rules=std.file(input="example.rules").result,
tags={
"Tag1": "Value1",
"Tag2": "Value2",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/networkfirewall"
"github.com/pulumi/pulumi-std/sdk/go/std"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
invokeFile, err := std.File(ctx, &std.FileArgs{
Input: "example.rules",
}, nil)
if err != nil {
return err
}
_, err = networkfirewall.NewRuleGroup(ctx, "example", &networkfirewall.RuleGroupArgs{
Capacity: pulumi.Int(100),
Name: pulumi.String("example"),
Type: pulumi.String("STATEFUL"),
Rules: pulumi.String(invokeFile.Result),
Tags: pulumi.StringMap{
"Tag1": pulumi.String("Value1"),
"Tag2": pulumi.String("Value2"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
using Std = Pulumi.Std;
return await Deployment.RunAsync(() =>
{
var example = new Aws.NetworkFirewall.RuleGroup("example", new()
{
Capacity = 100,
Name = "example",
Type = "STATEFUL",
Rules = Std.File.Invoke(new()
{
Input = "example.rules",
}).Apply(invoke => invoke.Result),
Tags =
{
{ "Tag1", "Value1" },
{ "Tag2", "Value2" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.networkfirewall.RuleGroup;
import com.pulumi.aws.networkfirewall.RuleGroupArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.FileArgs;
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 example = new RuleGroup("example", RuleGroupArgs.builder()
.capacity(100)
.name("example")
.type("STATEFUL")
.rules(StdFunctions.file(FileArgs.builder()
.input("example.rules")
.build()).result())
.tags(Map.ofEntries(
Map.entry("Tag1", "Value1"),
Map.entry("Tag2", "Value2")
))
.build());
}
}
resources:
example:
type: aws:networkfirewall:RuleGroup
properties:
capacity: 100
name: example
type: STATEFUL
rules:
fn::invoke:
function: std:file
arguments:
input: example.rules
return: result
tags:
Tag1: Value1
Tag2: Value2
The rules property accepts Suricata-format rules as a string, with one rule per line. This approach bypasses the ruleGroup property entirely, letting you import existing rule files without converting them to Pulumi’s structured format. Use this when you already have Suricata rules and want to preserve them as-is.
Define reusable variables for Suricata rules
Complex rule sets benefit from variables that define IP ranges and port lists once, then reference them across multiple rules.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as std from "@pulumi/std";
const example = new aws.networkfirewall.RuleGroup("example", {
capacity: 100,
name: "example",
type: "STATEFUL",
ruleGroup: {
ruleVariables: {
ipSets: [
{
key: "WEBSERVERS_HOSTS",
ipSet: {
definitions: [
"10.0.0.0/16",
"10.0.1.0/24",
"192.168.0.0/16",
],
},
},
{
key: "EXTERNAL_HOST",
ipSet: {
definitions: ["1.2.3.4/32"],
},
},
],
portSets: [{
key: "HTTP_PORTS",
portSet: {
definitions: [
"443",
"80",
],
},
}],
},
rulesSource: {
rulesString: std.file({
input: "suricata_rules_file",
}).then(invoke => invoke.result),
},
},
tags: {
Tag1: "Value1",
Tag2: "Value2",
},
});
import pulumi
import pulumi_aws as aws
import pulumi_std as std
example = aws.networkfirewall.RuleGroup("example",
capacity=100,
name="example",
type="STATEFUL",
rule_group={
"rule_variables": {
"ip_sets": [
{
"key": "WEBSERVERS_HOSTS",
"ip_set": {
"definitions": [
"10.0.0.0/16",
"10.0.1.0/24",
"192.168.0.0/16",
],
},
},
{
"key": "EXTERNAL_HOST",
"ip_set": {
"definitions": ["1.2.3.4/32"],
},
},
],
"port_sets": [{
"key": "HTTP_PORTS",
"port_set": {
"definitions": [
"443",
"80",
],
},
}],
},
"rules_source": {
"rules_string": std.file(input="suricata_rules_file").result,
},
},
tags={
"Tag1": "Value1",
"Tag2": "Value2",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/networkfirewall"
"github.com/pulumi/pulumi-std/sdk/go/std"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
invokeFile, err := std.File(ctx, &std.FileArgs{
Input: "suricata_rules_file",
}, nil)
if err != nil {
return err
}
_, err = networkfirewall.NewRuleGroup(ctx, "example", &networkfirewall.RuleGroupArgs{
Capacity: pulumi.Int(100),
Name: pulumi.String("example"),
Type: pulumi.String("STATEFUL"),
RuleGroup: &networkfirewall.RuleGroupRuleGroupArgs{
RuleVariables: &networkfirewall.RuleGroupRuleGroupRuleVariablesArgs{
IpSets: networkfirewall.RuleGroupRuleGroupRuleVariablesIpSetArray{
&networkfirewall.RuleGroupRuleGroupRuleVariablesIpSetArgs{
Key: pulumi.String("WEBSERVERS_HOSTS"),
IpSet: &networkfirewall.RuleGroupRuleGroupRuleVariablesIpSetIpSetArgs{
Definitions: pulumi.StringArray{
pulumi.String("10.0.0.0/16"),
pulumi.String("10.0.1.0/24"),
pulumi.String("192.168.0.0/16"),
},
},
},
&networkfirewall.RuleGroupRuleGroupRuleVariablesIpSetArgs{
Key: pulumi.String("EXTERNAL_HOST"),
IpSet: &networkfirewall.RuleGroupRuleGroupRuleVariablesIpSetIpSetArgs{
Definitions: pulumi.StringArray{
pulumi.String("1.2.3.4/32"),
},
},
},
},
PortSets: networkfirewall.RuleGroupRuleGroupRuleVariablesPortSetArray{
&networkfirewall.RuleGroupRuleGroupRuleVariablesPortSetArgs{
Key: pulumi.String("HTTP_PORTS"),
PortSet: &networkfirewall.RuleGroupRuleGroupRuleVariablesPortSetPortSetArgs{
Definitions: pulumi.StringArray{
pulumi.String("443"),
pulumi.String("80"),
},
},
},
},
},
RulesSource: &networkfirewall.RuleGroupRuleGroupRulesSourceArgs{
RulesString: pulumi.String(invokeFile.Result),
},
},
Tags: pulumi.StringMap{
"Tag1": pulumi.String("Value1"),
"Tag2": pulumi.String("Value2"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
using Std = Pulumi.Std;
return await Deployment.RunAsync(() =>
{
var example = new Aws.NetworkFirewall.RuleGroup("example", new()
{
Capacity = 100,
Name = "example",
Type = "STATEFUL",
RuleGroupConfiguration = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupArgs
{
RuleVariables = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRuleVariablesArgs
{
IpSets = new[]
{
new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRuleVariablesIpSetArgs
{
Key = "WEBSERVERS_HOSTS",
IpSet = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRuleVariablesIpSetIpSetArgs
{
Definitions = new[]
{
"10.0.0.0/16",
"10.0.1.0/24",
"192.168.0.0/16",
},
},
},
new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRuleVariablesIpSetArgs
{
Key = "EXTERNAL_HOST",
IpSet = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRuleVariablesIpSetIpSetArgs
{
Definitions = new[]
{
"1.2.3.4/32",
},
},
},
},
PortSets = new[]
{
new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRuleVariablesPortSetArgs
{
Key = "HTTP_PORTS",
PortSet = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRuleVariablesPortSetPortSetArgs
{
Definitions = new[]
{
"443",
"80",
},
},
},
},
},
RulesSource = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceArgs
{
RulesString = Std.File.Invoke(new()
{
Input = "suricata_rules_file",
}).Apply(invoke => invoke.Result),
},
},
Tags =
{
{ "Tag1", "Value1" },
{ "Tag2", "Value2" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.networkfirewall.RuleGroup;
import com.pulumi.aws.networkfirewall.RuleGroupArgs;
import com.pulumi.aws.networkfirewall.inputs.RuleGroupRuleGroupArgs;
import com.pulumi.aws.networkfirewall.inputs.RuleGroupRuleGroupRuleVariablesArgs;
import com.pulumi.aws.networkfirewall.inputs.RuleGroupRuleGroupRulesSourceArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.FileArgs;
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 example = new RuleGroup("example", RuleGroupArgs.builder()
.capacity(100)
.name("example")
.type("STATEFUL")
.ruleGroup(RuleGroupRuleGroupArgs.builder()
.ruleVariables(RuleGroupRuleGroupRuleVariablesArgs.builder()
.ipSets(
RuleGroupRuleGroupRuleVariablesIpSetArgs.builder()
.key("WEBSERVERS_HOSTS")
.ipSet(RuleGroupRuleGroupRuleVariablesIpSetIpSetArgs.builder()
.definitions(
"10.0.0.0/16",
"10.0.1.0/24",
"192.168.0.0/16")
.build())
.build(),
RuleGroupRuleGroupRuleVariablesIpSetArgs.builder()
.key("EXTERNAL_HOST")
.ipSet(RuleGroupRuleGroupRuleVariablesIpSetIpSetArgs.builder()
.definitions("1.2.3.4/32")
.build())
.build())
.portSets(RuleGroupRuleGroupRuleVariablesPortSetArgs.builder()
.key("HTTP_PORTS")
.portSet(RuleGroupRuleGroupRuleVariablesPortSetPortSetArgs.builder()
.definitions(
"443",
"80")
.build())
.build())
.build())
.rulesSource(RuleGroupRuleGroupRulesSourceArgs.builder()
.rulesString(StdFunctions.file(FileArgs.builder()
.input("suricata_rules_file")
.build()).result())
.build())
.build())
.tags(Map.ofEntries(
Map.entry("Tag1", "Value1"),
Map.entry("Tag2", "Value2")
))
.build());
}
}
resources:
example:
type: aws:networkfirewall:RuleGroup
properties:
capacity: 100
name: example
type: STATEFUL
ruleGroup:
ruleVariables:
ipSets:
- key: WEBSERVERS_HOSTS
ipSet:
definitions:
- 10.0.0.0/16
- 10.0.1.0/24
- 192.168.0.0/16
- key: EXTERNAL_HOST
ipSet:
definitions:
- 1.2.3.4/32
portSets:
- key: HTTP_PORTS
portSet:
definitions:
- '443'
- '80'
rulesSource:
rulesString:
fn::invoke:
function: std:file
arguments:
input: suricata_rules_file
return: result
tags:
Tag1: Value1
Tag2: Value2
The ruleVariables property defines ipSets and portSets that your Suricata rules can reference by name. This centralizes network definitions, making rules easier to maintain. The rulesString property contains the actual Suricata rules, which can reference variables like $WEBSERVERS_HOSTS and $HTTP_PORTS.
Publish metrics from stateless rules
Stateless inspection evaluates packets individually without tracking connection state, enabling high-performance filtering with custom CloudWatch metrics.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.networkfirewall.RuleGroup("example", {
description: "Stateless Rate Limiting Rule",
capacity: 100,
name: "example",
type: "STATELESS",
ruleGroup: {
rulesSource: {
statelessRulesAndCustomActions: {
customActions: [{
actionDefinition: {
publishMetricAction: {
dimensions: [{
value: "2",
}],
},
},
actionName: "ExampleMetricsAction",
}],
statelessRules: [{
priority: 1,
ruleDefinition: {
actions: [
"aws:pass",
"ExampleMetricsAction",
],
matchAttributes: {
sources: [{
addressDefinition: "1.2.3.4/32",
}],
sourcePorts: [{
fromPort: 443,
toPort: 443,
}],
destinations: [{
addressDefinition: "124.1.1.5/32",
}],
destinationPorts: [{
fromPort: 443,
toPort: 443,
}],
protocols: [6],
tcpFlags: [{
flags: ["SYN"],
masks: [
"SYN",
"ACK",
],
}],
},
},
}],
},
},
},
tags: {
Tag1: "Value1",
Tag2: "Value2",
},
});
import pulumi
import pulumi_aws as aws
example = aws.networkfirewall.RuleGroup("example",
description="Stateless Rate Limiting Rule",
capacity=100,
name="example",
type="STATELESS",
rule_group={
"rules_source": {
"stateless_rules_and_custom_actions": {
"custom_actions": [{
"action_definition": {
"publish_metric_action": {
"dimensions": [{
"value": "2",
}],
},
},
"action_name": "ExampleMetricsAction",
}],
"stateless_rules": [{
"priority": 1,
"rule_definition": {
"actions": [
"aws:pass",
"ExampleMetricsAction",
],
"match_attributes": {
"sources": [{
"address_definition": "1.2.3.4/32",
}],
"source_ports": [{
"from_port": 443,
"to_port": 443,
}],
"destinations": [{
"address_definition": "124.1.1.5/32",
}],
"destination_ports": [{
"from_port": 443,
"to_port": 443,
}],
"protocols": [6],
"tcp_flags": [{
"flags": ["SYN"],
"masks": [
"SYN",
"ACK",
],
}],
},
},
}],
},
},
},
tags={
"Tag1": "Value1",
"Tag2": "Value2",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/networkfirewall"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := networkfirewall.NewRuleGroup(ctx, "example", &networkfirewall.RuleGroupArgs{
Description: pulumi.String("Stateless Rate Limiting Rule"),
Capacity: pulumi.Int(100),
Name: pulumi.String("example"),
Type: pulumi.String("STATELESS"),
RuleGroup: &networkfirewall.RuleGroupRuleGroupArgs{
RulesSource: &networkfirewall.RuleGroupRuleGroupRulesSourceArgs{
StatelessRulesAndCustomActions: &networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsArgs{
CustomActions: networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsCustomActionArray{
&networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsCustomActionArgs{
ActionDefinition: &networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsCustomActionActionDefinitionArgs{
PublishMetricAction: &networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsCustomActionActionDefinitionPublishMetricActionArgs{
Dimensions: networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsCustomActionActionDefinitionPublishMetricActionDimensionArray{
&networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsCustomActionActionDefinitionPublishMetricActionDimensionArgs{
Value: pulumi.String("2"),
},
},
},
},
ActionName: pulumi.String("ExampleMetricsAction"),
},
},
StatelessRules: networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleArray{
&networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleArgs{
Priority: pulumi.Int(1),
RuleDefinition: &networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionArgs{
Actions: pulumi.StringArray{
pulumi.String("aws:pass"),
pulumi.String("ExampleMetricsAction"),
},
MatchAttributes: &networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesArgs{
Sources: networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesSourceArray{
&networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesSourceArgs{
AddressDefinition: pulumi.String("1.2.3.4/32"),
},
},
SourcePorts: networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesSourcePortArray{
&networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesSourcePortArgs{
FromPort: pulumi.Int(443),
ToPort: pulumi.Int(443),
},
},
Destinations: networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesDestinationArray{
&networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesDestinationArgs{
AddressDefinition: pulumi.String("124.1.1.5/32"),
},
},
DestinationPorts: networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesDestinationPortArray{
&networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesDestinationPortArgs{
FromPort: pulumi.Int(443),
ToPort: pulumi.Int(443),
},
},
Protocols: pulumi.IntArray{
pulumi.Int(6),
},
TcpFlags: networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesTcpFlagArray{
&networkfirewall.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesTcpFlagArgs{
Flags: pulumi.StringArray{
pulumi.String("SYN"),
},
Masks: pulumi.StringArray{
pulumi.String("SYN"),
pulumi.String("ACK"),
},
},
},
},
},
},
},
},
},
},
Tags: pulumi.StringMap{
"Tag1": pulumi.String("Value1"),
"Tag2": pulumi.String("Value2"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.NetworkFirewall.RuleGroup("example", new()
{
Description = "Stateless Rate Limiting Rule",
Capacity = 100,
Name = "example",
Type = "STATELESS",
RuleGroupConfiguration = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupArgs
{
RulesSource = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceArgs
{
StatelessRulesAndCustomActions = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsArgs
{
CustomActions = new[]
{
new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsCustomActionArgs
{
ActionDefinition = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsCustomActionActionDefinitionArgs
{
PublishMetricAction = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsCustomActionActionDefinitionPublishMetricActionArgs
{
Dimensions = new[]
{
new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsCustomActionActionDefinitionPublishMetricActionDimensionArgs
{
Value = "2",
},
},
},
},
ActionName = "ExampleMetricsAction",
},
},
StatelessRules = new[]
{
new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleArgs
{
Priority = 1,
RuleDefinition = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionArgs
{
Actions = new[]
{
"aws:pass",
"ExampleMetricsAction",
},
MatchAttributes = new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesArgs
{
Sources = new[]
{
new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesSourceArgs
{
AddressDefinition = "1.2.3.4/32",
},
},
SourcePorts = new[]
{
new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesSourcePortArgs
{
FromPort = 443,
ToPort = 443,
},
},
Destinations = new[]
{
new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesDestinationArgs
{
AddressDefinition = "124.1.1.5/32",
},
},
DestinationPorts = new[]
{
new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesDestinationPortArgs
{
FromPort = 443,
ToPort = 443,
},
},
Protocols = new[]
{
6,
},
TcpFlags = new[]
{
new Aws.NetworkFirewall.Inputs.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesTcpFlagArgs
{
Flags = new[]
{
"SYN",
},
Masks = new[]
{
"SYN",
"ACK",
},
},
},
},
},
},
},
},
},
},
Tags =
{
{ "Tag1", "Value1" },
{ "Tag2", "Value2" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.networkfirewall.RuleGroup;
import com.pulumi.aws.networkfirewall.RuleGroupArgs;
import com.pulumi.aws.networkfirewall.inputs.RuleGroupRuleGroupArgs;
import com.pulumi.aws.networkfirewall.inputs.RuleGroupRuleGroupRulesSourceArgs;
import com.pulumi.aws.networkfirewall.inputs.RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsArgs;
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 example = new RuleGroup("example", RuleGroupArgs.builder()
.description("Stateless Rate Limiting Rule")
.capacity(100)
.name("example")
.type("STATELESS")
.ruleGroup(RuleGroupRuleGroupArgs.builder()
.rulesSource(RuleGroupRuleGroupRulesSourceArgs.builder()
.statelessRulesAndCustomActions(RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsArgs.builder()
.customActions(RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsCustomActionArgs.builder()
.actionDefinition(RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsCustomActionActionDefinitionArgs.builder()
.publishMetricAction(RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsCustomActionActionDefinitionPublishMetricActionArgs.builder()
.dimensions(RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsCustomActionActionDefinitionPublishMetricActionDimensionArgs.builder()
.value("2")
.build())
.build())
.build())
.actionName("ExampleMetricsAction")
.build())
.statelessRules(RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleArgs.builder()
.priority(1)
.ruleDefinition(RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionArgs.builder()
.actions(
"aws:pass",
"ExampleMetricsAction")
.matchAttributes(RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesArgs.builder()
.sources(RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesSourceArgs.builder()
.addressDefinition("1.2.3.4/32")
.build())
.sourcePorts(RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesSourcePortArgs.builder()
.fromPort(443)
.toPort(443)
.build())
.destinations(RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesDestinationArgs.builder()
.addressDefinition("124.1.1.5/32")
.build())
.destinationPorts(RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesDestinationPortArgs.builder()
.fromPort(443)
.toPort(443)
.build())
.protocols(6)
.tcpFlags(RuleGroupRuleGroupRulesSourceStatelessRulesAndCustomActionsStatelessRuleRuleDefinitionMatchAttributesTcpFlagArgs.builder()
.flags("SYN")
.masks(
"SYN",
"ACK")
.build())
.build())
.build())
.build())
.build())
.build())
.build())
.tags(Map.ofEntries(
Map.entry("Tag1", "Value1"),
Map.entry("Tag2", "Value2")
))
.build());
}
}
resources:
example:
type: aws:networkfirewall:RuleGroup
properties:
description: Stateless Rate Limiting Rule
capacity: 100
name: example
type: STATELESS
ruleGroup:
rulesSource:
statelessRulesAndCustomActions:
customActions:
- actionDefinition:
publishMetricAction:
dimensions:
- value: '2'
actionName: ExampleMetricsAction
statelessRules:
- priority: 1
ruleDefinition:
actions:
- aws:pass
- ExampleMetricsAction
matchAttributes:
sources:
- addressDefinition: 1.2.3.4/32
sourcePorts:
- fromPort: 443
toPort: 443
destinations:
- addressDefinition: 124.1.1.5/32
destinationPorts:
- fromPort: 443
toPort: 443
protocols:
- 6
tcpFlags:
- flags:
- SYN
masks:
- SYN
- ACK
tags:
Tag1: Value1
Tag2: Value2
Stateless rules match on packet headers (IPs, ports, protocols, TCP flags) without tracking connections. The customActions property defines a publishMetricAction that emits CloudWatch metrics when the rule matches. The matchAttributes property specifies the 5-tuple to match, and the actions array can include both standard actions (aws:pass, aws:drop) and custom metric actions.
Beyond these examples
These snippets focus on specific rule group features: stateful domain and IP-based filtering, Suricata rule import and variables, and stateless inspection with custom metrics. They’re intentionally minimal rather than full firewall configurations.
The examples may reference pre-existing infrastructure such as Network Firewall policies (rule groups attach to policies), VPC and subnets where firewall endpoints are deployed, and S3 buckets for rule file storage. They focus on configuring the rule group rather than provisioning the surrounding firewall infrastructure.
To keep things focused, common rule group patterns are omitted, including:
- Rule group attachment to firewall policies
- Stateful rule ordering and priority
- Encryption configuration (encryptionConfiguration)
- IP set references for dynamic allow/deny lists
These omissions are intentional: the goal is to illustrate how each rule group feature is wired, not provide drop-in firewall modules. See the Network Firewall RuleGroup resource reference for all available configuration options.
Let's configure AWS Network Firewall Rule Groups
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Rule Group Basics & Configuration
type property with values STATEFUL or STATELESS.capacity and name are immutable properties that force resource replacement if changed. Plan your capacity carefully upfront based on your rule requirements.ruleGroup or rules, not both. Use ruleGroup for structured rule definitions with rule variables and multiple rule types. Use rules for importing existing Suricata-compatible rules in flat format.Rule Formats & Sources
Yes, you have two options:
- Flat format - Use the
rulesproperty with one rule per line - With variables - Use
ruleGroup.rulesSource.rulesStringto combine Suricata rules with rule variables
aws.s3.getObject to fetch the rules file from S3, then pass the body content to ruleGroup.rulesSource.rulesString.ruleGroup.ruleVariables with ipSets and portSets blocks to define variables like HOME_NET or HTTP_PORTS that can be referenced in your Suricata rules.Stateful Rules
STATEFUL rule group with rulesSource.rulesSourceList, setting generatedRulesType to DENYLIST, targetTypes to ["HTTP_HOST"], and targets to your domain list.rulesSource.statefulRules with action set to PASS or DROP, and configure the header block with source/destination IPs, ports, protocol, and direction.Stateless Rules
publishMetricAction let you define additional actions beyond standard ones (e.g., aws:pass). You can use them to publish CloudWatch metrics or perform other custom processing alongside packet handling.