

# Working with stateful rule groups in AWS Network Firewall
<a name="stateful-rule-groups-ips"></a>

A stateful rule group is a rule group that uses Suricata compatible intrusion prevention system (IPS) specifications. Suricata is an open source network IPS that includes a standard rule-based language for stateful network traffic inspection. 

Stateful rule groups have a configurable top-level setting called `StatefulRuleOptions`, which contains the `RuleOrder` attribute. You can set this in the console when you create a rule group, or in the API under `StatefulRuleOptions`. You can't change the `RuleOrder` after the rule group is created. 

You can enter any stateful rule in Suricata compatible strings. For standard Suricata rules specifications and for domain list inspection, you can alternately provide specifications to Network Firewall and have Network Firewall create the Suricata compatible strings for you. 

As needed, depending on the rules that you provide, the stateful engine performs deep packet inspection (DPI) of your traffic flows. DPI inspects and processes the payload data within your packets, rather than just the header information. 

The rest of this section provides requirements and additional information for using Suricata compatible rules with Network Firewall. 

**Note**  
This section and others that describe Suricata-based concepts are not intended to replace or duplicate information from the Suricata documentation. For more Suricata-specific information, see the [Suricata documentation](https://docs.suricata.io/en/suricata-7.0.8/).

**Previous Suricata major version upgrade**  
When Network Firewall upgrades to a new major version of Suricata, related changes are tracked here.

Network Firewall upgraded from Suricata version 6.0.9 to 7.0 in November of 2024. For full information about the upgrade from version 6.0.9, see [Upgrading 6.0 to 7.0](https://docs.suricata.io/en/latest/upgrade.html#upgrading-6-0-to-7-0). 

The following are examples of the changes in that upgrade: 
+ PCRE 1 rule format is no longer supported, and has been replaced with PCRE2.
+ When you specify a sticky buffer in a rule, it needs to be immediately followed by the payload keywords. For example, keywords such as `dns.query` and `tls.sni` must be followed by a content modifier. 
+ Keywords that use ranges, such as `itype` now require the range to be specified with the format `min:max`. 

**Topics**
+ [Creating a stateful rule group](rule-group-stateful-creating.md)
+ [Updating a stateful rule group](rule-group-stateful-updating.md)
+ [Deleting a stateful rule group](rule-group-stateful-deleting.md)
+ [Managing evaluation order for Suricata compatible rules in AWS Network Firewall](suricata-rule-evaluation-order.md)
+ [Limitations and caveats for stateful rules in AWS Network Firewall](suricata-limitations-caveats.md)
+ [Best practices for writing Suricata compatible rules for AWS Network Firewall](suricata-best-practices.md)
+ [Examples of stateful rules for Network Firewall](suricata-examples.md)

# Creating a stateful rule group
<a name="rule-group-stateful-creating"></a>

This section provides guidance for creating a stateful rule group.

**To create a stateful rule group**

1. Sign in to the AWS Management Console and open the Amazon VPC console at [https://console.aws.amazon.com/vpc/](https://console.aws.amazon.com/vpc/).

1. In the navigation pane, under **Network Firewall**, choose **Network Firewall rule groups**.

1. Choose **Create Network Firewall rule group**. 

1. Under **Choose rule group type**, for the **Rule group format**, choose **Stateful rule group**. 

   For **Rule evaluation order**, choose the way that your stateful rules are ordered for evaluation: 
   + Choose **Strict order** (recommended) to provide your rules in the order that you want them to be evaluated. You can then choose one or more default actions for packets that don't match any rules.
   + Choose **Action order** to have the stateful rules engine determine the evaluation order of your rules. The default action for this rule order is **Pass**, followed by **Drop**, **Reject**, and **Alert** actions. This option was previously named **Default** order.

   For more information about stateful default actions for rule groups, see [Action orderAction order](suricata-rule-evaluation-order.md#suricata-default-rule-evaluation-order).

   For more information about stateful rule groups, see [Working with stateful rule groups in AWS Network Firewall](stateful-rule-groups-ips.md). 

1. Choose **Next**.

1. Enter a **Name** to identify this rule group. 
**Note**  
You can't change the name after you create the rule group.

1. (Optional) Enter a **Description** for the rule group to help you identify ot among your other resources.

1. For **Capacity**, set the maximum capacity you want to allow for the stateful rule group, up to the maximum of 50,000. You can't change this setting after you create the rule group. For information about how to calculate this, see [Setting rule group capacity in AWS Network Firewall](nwfw-rule-group-capacity.md). For information about the maximum setting, see [AWS Network Firewall quotas](quotas.md). 

1. Choose **Next**.

1. Select the type of rule group that you want to add, from the **Stateful rule group options**. The rest of your rule group specifications depend on the option you choose.
**Note**  
If you need to specify options that aren't available through the console, you can use one of the APIs or AWS CloudFormation. For information, see [StatefulRule](https://docs.aws.amazon.com/network-firewall/latest/APIReference/API_StatefulRule.html) in the *AWS Network Firewall API Reference* and [AWS::NetworkFirewall::RuleGroup StatefulRule](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-statefulrule.html) in the *AWS CloudFormation User Guide*.
   + (Option) **Standard stateful rule** – Entry form for a basic Suricata rule.

     For each rule that you want in your rule group, specify the following information and then choose **Add rule**. Your added rules are listed in the **Rules** list. 
     + Choose the protocol and source and destination settings for your rule. 
     + For **Traffic direction**, choose whether to apply the rule to any direction or only for traffic that flows forward, from the specified source to the specified destination.
**Note**  
Network Firewall doesn't automatically add the direction keyword `to_server`, and will inspect all the packets in the flow, irrespective of the flow state.
     + For **Action**, select the action that you want Network Firewall to take when a packet matches the rule settings. For information on these options, see [Actions for stateful rules](rule-action.md#rule-action-stateful). 

     To define IP sets and ports as variables that you can reference in your rules: 
     + In the **Rule variables** section, enter variables and values for **IP set variables** and **Port variables**.

     To add one or more references to IP set resources, such as Amazon VPC prefix lists, that you can use as variables in your rules: 
     + In the **IP set reference** section, enter a **IP set variable name** and select an **IP set reference ID**. The **IP set reference ID** corresponds to the resource ID of the IP set Amazon Resource Name (ARN) that you want to reference. Network Firewall currently supports Amazon VPC prefix lists and resource groups as IP set references. For more information about working with IP set references in Network Firewall, see [Referencing Amazon VPC prefix lists](rule-groups-ip-set-references.md#rule-groups-referencing-prefix-lists).

     For enhanced filtering options, you can specify the following:

     **Geographic IP filtering - **To filter traffic based on country:
     + Choose to enable **Geographic IP filtering** 
     + Select the matching option:
       + Match only selected countries
       + Match all but selected countries
     + Choose the **Geographic IP traffic direction** (source, destination, or any)
     + Choose the **Country codes** from the dropdown list 
     + For more information, see [Geographic IP filtering in Suricata compatible AWS Network Firewall rule groups](rule-groups-geo-ip-filtering.md)

     **URL and Domain Category filtering - **To filter traffic based on web content categories:
     + Choose to enable **URL and Domain Category filtering**
     + Select the matching option:
       + Match all selected categories
       + Match all unselected categories
     + Choose the **AWS category type:**
       + aws\$1url\$1category (for HTTP protocol, requires TLS inspection for HTTPS)
       + aws\$1domain\$1category (for TLS and HTTP protocols)
     + Choose the **categories** from the dropdown list 
     + For more information, see [URL and Domain Category Filtering in Suricata compatible AWS Network Firewall rule groups](rule-groups-url-filtering.md)

     For information about these rules, see [Standard stateful rule groups in AWS Network Firewall](stateful-rule-groups-basic.md).
   + (Option) **Domain list** – Specify the following information. 
**Note**  
You can create domain list rules from traffic analysis reports. For information, see [Creating stateful rule groups from reports](reporting.md#creating-stateful-rule-groups-from-reports). 
     + For **Domain name source**, enter the domain names that you want to inspect for, one name specification per line. Valid domain name specifications are the following: 
       + Explicit names. For example, `abc.example.com` matches only the domain `abc.example.com`.
       + Names that use a domain wildcard, which you indicate with an initial '`.`'. For example,`.example.com` matches `example.com` and matches all subdomains of `example.com`, such as `abc.example.com` and `www.example.com`. 
     + For **CIDR ranges**, choose whether to inspect default or custom ranges.
     + For **Protocols**, choose the protocols you want to inspect. 
     + For **Action**, select the list type that you are creating, either **Allow** or **Deny**. For information on these options, see [Actions for stateful rules](rule-action.md#rule-action-stateful). 

     For information about stateful domain name rules, see [Stateful domain list rule groups in AWS Network Firewall](stateful-rule-groups-domain-names.md).
   + (Option) **Suricata compatible rule string**

     To define IP sets and ports as variables that you can reference in your rules: 
     + In the **Rule variables** section, enter variables and values for **IP set variables** and **Port variables**.

     To add one or more references to IP set resources, such as Amazon VPC prefix lists, that you can use as variables in your rules: 
     + In the **IP set reference** section, enter a **IP set variable name** and select an **IP set reference ID**. The **IP set reference ID** corresponds to the resource ID of the IP set Amazon Resource Name (ARN) that you want to reference. Network Firewall currently supports Amazon VPC prefix lists and resource groups as IP set references. For more information about working with IP set references in Network Firewall, see [Referencing Amazon VPC prefix lists](rule-groups-ip-set-references.md#rule-groups-referencing-prefix-lists).

     Paste your rules into the text box.

1. Choose **Next**.

1. (Optional) On the **Configure advanced settings** page, under **Customer managed key**, toggle the **Customize encryption settings** option to configure your customer managed key. For more information about this option, see [Encryption at rest with AWS Key Management Service](kms-encryption-at-rest.md).

1. Choose **Next**.

1. (Optional) On the **Add tags** page, enter a key and optional value for any tag that you want added to this firewall policy. Tags help you organize and manage your AWS resources. For more information about tagging your resources, see [Tagging AWS Network Firewall resources](tagging.md). 

1. Choose **Next**.

1. Review the settings that you've provided for the rule group, then choose **Create stateful rule group**.

Your new rule group is added to the list in the **Network Firewall rule groups** page.

To use your rule group in a firewall policy, follow the procedures at [Managing your firewall policy](firewall-policy-managing.md).

# Updating a stateful rule group
<a name="rule-group-stateful-updating"></a>

To change your stateful rule group settings, use the following procedure.

**To update a stateful rule group**

1. Sign in to the AWS Management Console and open the Amazon VPC console at [https://console.aws.amazon.com/vpc/](https://console.aws.amazon.com/vpc/).

1. In the navigation pane, under **Network Firewall**, choose **Network Firewall rule groups**.

1. In the **Network Firewall rule groups** page, choose the name of the rule group that you want to update. The rule group's details page appears. 

1. In your rule group's details page, in the area that you want to change, choose **Edit**. Follow the prompts to make your updates. The interface varies according to the rule group type. When you're done editing an area, choose **Save** to save your changes in the rule group.

**How Network Firewall propagates your changes**  
When you make any changes to a firewall, including changes to any of the firewall's components, like rule groups, TLS inspection configurations, and firewall policies, Network Firewall propagates the changes everywhere that the firewall is used. Your changes are normally applied within minutes, but there might be a brief period of inconsistency when the changes have arrived in some places and not in others. For example, if you modify a rule group so that it drops an additional type of packet, for a firewall that uses the rule group, the new packet type might briefly be dropped by one firewall endpoint while still being allowed by another. 

This temporary inconsistency can occur when you first create a firewall and when you make changes to an existing firewall. Generally, any inconsistencies of this type last only a few seconds. 

When you add a TLS inspection configuration to an existing firewall, Network Firewall interrupts traffic flows that match the criteria defined by the TLS inspection configuration scope configuration. Network Firewall will begin SSL/TLS decryption and inspection for new connections to the firewall.

Changes to stateful rules are applied only to new traffic flows. Other firewall changes, including changes to stateless rules, are applied to all network packets. 

# Deleting a stateful rule group
<a name="rule-group-stateful-deleting"></a>

To delete a rule group, use the guidance in this section.

**Deleting a rule group, TLS inspection configuration, or firewall policy**  
When you delete a rule group, TLS inspection configuration, or a firewall policy, AWS Network Firewall checks to see if it's currently being referenced. A rule group and TLS inspection configuration can be referenced by a firewall policy, and a firewall policy can be referenced by a firewall. If Network Firewall determines that the resource is being referenced, it warns you. Network Firewall is almost always able to determine whether a resource is being referenced. However, in rare cases, it might not be able to do so. If you need to be sure that the resource that you want to delete isn't in use, check all of your firewalls or firewall policies before deleting it. Note that policies that have associations can't be deleted.

**To delete a stateful rule group**

1. Sign in to the AWS Management Console and open the Amazon VPC console at [https://console.aws.amazon.com/vpc/](https://console.aws.amazon.com/vpc/).

1. In the navigation pane, under **Network Firewall**, choose **Network Firewall rule groups**.

1. In the **Network Firewall rule groups** page, select the name of the rule group that you want to delete, and then choose **Delete**.

**How Network Firewall propagates your changes**  
When you make any changes to a firewall, including changes to any of the firewall's components, like rule groups, TLS inspection configurations, and firewall policies, Network Firewall propagates the changes everywhere that the firewall is used. Your changes are normally applied within minutes, but there might be a brief period of inconsistency when the changes have arrived in some places and not in others. For example, if you modify a rule group so that it drops an additional type of packet, for a firewall that uses the rule group, the new packet type might briefly be dropped by one firewall endpoint while still being allowed by another. 

This temporary inconsistency can occur when you first create a firewall and when you make changes to an existing firewall. Generally, any inconsistencies of this type last only a few seconds. 

Changes to stateful rules are applied only to new traffic flows. Other firewall changes, including changes to stateless rules, are applied to all network packets. 

# Managing evaluation order for Suricata compatible rules in AWS Network Firewall
<a name="suricata-rule-evaluation-order"></a>

You can configure and manage the evaluation order of the rules in your Suricata compatible stateful rule groups. 

All of your stateful rule groups are provided to the rule engine as Suricata compatible strings. Suricata can evaluate stateful rule groups by using the default rule group ordering method, or you can set an exact order using the *strict* ordering method. We recommend that you use strict order because it lets you specify the exact order that you'd like the stateful engine to evaluation your rules. The settings for your rule groups must match the settings for the firewall policy that they belong to.

## Action order
<a name="suricata-default-rule-evaluation-order"></a>

If your firewall policy is set up to use action order rule group ordering, the action order by which Suricata evaluates stateful rules is determined by the following settings, listed in order of precedence:

1. The Suricata `action` specification. This takes highest precedence. 

   Actions are processed in the following order:

   1. `pass`

   1. `drop`

   1. `reject`

   1. `alert`
**Note**  
If a packet within a flow matches a rule containing `pass` action, then Suricata doesn't scan the other packets in that flow and it passes the unscanned packets. 

   For more information about the action specification, see [Suricata.yaml: Action-order](https://docs.suricata.io/en/suricata-7.0.8/configuration/suricata-yaml.html?highlight=action+order#action-order) in the [Suricata User Guide](https://docs.suricata.io/en/suricata-7.0.8/index.html).

1. The Suricata `priority` keyword. Within a specific action group, you can use the priority setting to indicate the processing order. By default, Suricata processes from the lowest numbered priority setting on up. The `priority` keyword has a mandatory numeric value ranging from 1 to 65535. Note that the `priority` keyword is only valid using the default action order.

   For more information about priority, see [Suricata.yaml: Action-order](https://docs.suricata.io/en/suricata-7.0.8/rules/meta.html?highlight=priority#priority) in the [Suricata User Guide](https://docs.suricata.io/en/suricata-7.0.8/index.html).

For example, Suricata evaluates all `pass` rules before evaluating any `drop`, `reject`, or `alert` rules by default, regardless of the value of priority settings. Within all `pass` rules, if priority keywords are present, Suricata orders the processing according to them.

The protocol layer does not impact the rule evaluation order by default. If you want to avoid matching against lower-level protocol packets before higher-level application protocols can be identified, consider using the `flow` keyword in your rules. This is needed because, for example, a TCP rule might match on the first packet of a TCP handshake before the stateful engine can identify the application protocol. For information about the `flow` keyword, see [Flow Keywords](https://docs.suricata.io/en/suricata-7.0.8/rules/flow-keywords.html).

For examples of default rule order management, see [Stateful rules examples: manage rule evaluation order](suricata-examples.md#suricata-example-rule-ordering).

For additional information about evaluation order for stateful rules, see the following topics in the [Suricata User Guide](https://docs.suricata.io/en/suricata-7.0.8/):
+ [Suricata.yaml: Action-order](https://docs.suricata.io/en/suricata-7.0.8/configuration/suricata-yaml.html?highlight=action%20order#action-order)
+ [Meta Keywords: priority](https://docs.suricata.io/en/suricata-7.0.8/rules/meta.html?highlight=priority#priority)

## Strict evaluation order
<a name="suricata-strict-rule-evaluation-order"></a>

If your firewall policy is set up to use strict ordering, Network Firewall allows you the option to manually set a *strict* rule group order. With strict ordering, the rule groups are evaluated by order of priority, starting from the lowest number, and the rules in each rule group are processed in the order in which they're defined.

When configuring these actions, consider the following caveats:

1. For drop actions, you can choose either none or only one drop action.

1. For alert actions, you can choose none, one alert action, or **Alert all** plus any of the other two alert actions.

1. Some combinations of actions are invalid. If either **Drop established** or **Alert established** is selected, you cannot select **Application Layer drop established** or **Application Layer alert established**, and vice versa.

1. When you choose **Strict** for your rule order, you can choose one or more **Default actions**. Note that this does not refer to default action rule ordering, but rather, to the default actions that Network Firewall takes when following your strict, or exact, rule ordering.

The default actions are as follows:

### Drop actions
<a name="suricata-strict-rule-evaluation-order-drop-actions"></a>

If you have rules that match application layer data, such as those that evaluate HTTP headers, a default drop action might trigger earlier than you want. This can happen when the data that your rules match against spans multiple packets, because a default drop action can apply to a single packet. For this case, don't choose any default drop action and instead use drop rules that are specific to the application layer. 

*Choose none or one. You can't choose more than one.*
+ **Drop all** – Drops all packets.
+ **Drop established** – Drops only the packets that are in established connections from client to server. This allows the layer 3 and 4 connection establishment packets that are needed for the upper-layer connections to be established, while dropping the packets for connections that are already established. This allows application-layer *pass* rules to be written in a default-deny setup without the need to write additional rules to allow the lower-layer handshaking parts of the underlying protocols. Packets from established connections from the server to the client are passed to allow return traffic from established connections back to the client.

  Choose this option when using strict order for your own domain list rule groups because Network Firewall requires an established connection in order to evaluate whether to pass or drop the packets for domain lists.

  For other protocols, such as UDP, Network Firewall considers the connection established only after seeing traffic from both sides of the connection. For connectionless protocols, such as UDP and ICMP, the `drop` established action drops all packets. You must write specific rules to allow these packets as needed.
+ **Application Layer drop established** – Drops server-initiated banner packets and packets in established connections. It also provides enhanced support for segmented application layer traffic through the following behaviors:
  + Allows segmented TLS client hello packets until a `TLS.SNI` field is detected, then applies rules based on SNI.
  + Allows segmented HTTPS request packets until the `HTTP.HOST` field is detected, then applies rules based on host

**About the application layer drop established action**  
When you select the application layer drop established option, the firewall drops connections that have banner packets. After a connection is established, if the firewall sees a packet that no explicit pass rule allows, the firewall drops that packet and all subsequent packets in the connection. This behavior affects TCP flow control packets that occur after the TCP handshake but before a pass rule applies. 

Examples of TCP flow control packets that can result in such drops include: 
+ TCP window updates from either client or server, if seen immediately after the TCP handshake.
+ TCP keep-alives from either client or server, if seen immediately after the TCP handshake.
+ TCP resets from either client or server, if seen immediately after the TCP handshake.

To allow these packets in your environment you can add custom pass rules in a stateful rule group, for example:

To allow TCP window packets:

```
pass tcp any any -> any any (msg:"Allow all TCP Window Updates from server to client"; tcp.flags:A; dsize:0; window:!0; flow:established, to_client; sid:1000001;)
pass tcp any any -> any any (msg:"Allow all TCP Window Updates from client to server"; tcp.flags:A; dsize:0; window:!0; flow:established, to_server; sid:1000002;)
```

To allow TCP keep-alives (will pass all ACKs):

```
pass tcp any any -> any any (msg:"Allow TCP keep alives - all acks - from server to client"; tcp.flags:A; dsize:0; flow:established, to_client; sid:1000003;)
pass tcp any any -> any any (msg:"Allow TCP keep alives - all acks - from client to server"; tcp.flags:A; dsize:0; flow:established, to_server; sid:1000004;)
```

To allow TCP resets:

```
pass tcp any any -> any any (msg:"Allow TCP resets from server to client"; tcp.flags:+R; dsize:0; flow:established, to_client; sid:1000005;)
pass tcp any any -> any any (msg:"Allow TCP resets from client to server"; tcp.flags:+R; dsize:0; flow:established, to_server; sid:1000006;)
```

### Alert actions
<a name="suricata-strict-rule-evaluation-order-drop-actions"></a>

*Choose none, one, or all.*
+ **Alert all** - Logs an `ALERT` message on all packets. This does not drop packets, but alerts you to what would be dropped if you were to choose **Drop all**.
+ **Alert established** - Logs an `ALERT` message on only the packets that are in established connections. This does not drop packets, but alerts you to what would be dropped if you were to choose **Drop established**.
+ **Application Layer alert established** – Logs an `ALERT` message on only the packets that are in established connections, with enhanced support for segmented application layer traffic.
**Tip**  
You can use these logged messages to better understand the impact that the Application Layer Drop Established action has on firewall behavior.

For more information about logging network traffic, see [Logging network traffic from AWS Network Firewall](firewall-logging.md).

# Limitations and caveats for stateful rules in AWS Network Firewall
<a name="suricata-limitations-caveats"></a>

AWS Network Firewall stateful rules are Suricata compatible. Most Suricata rules work out of the box with Network Firewall. Your use of Suricata rules with Network Firewall has the restrictions and caveats listed in this section. 

## Suricata features that Network Firewall doesn't support
<a name="suricata-not-supported"></a>

The following Suricata features are not supported by Network Firewall:
+ Datasets. The keywords `dataset` and `datarep` aren't allowed.
+ ENIP/CIP keywords. 
+ File extraction. File keywords aren't allowed. 
+ FTP-data protocol detection.
+ IP reputation. The `iprep` keyword is not allowed. 
+ Lua scripting.
+ Rules actions except for pass, drop, reject, and alert. Pass, drop, reject, and alert are supported. For additional information about stateful rule actions, see [Actions for stateful rules](rule-action.md#rule-action-stateful).
+ SCTP protocol.
+ `xbits` and `hostbits` with host or IP-level tracking (`track ip_src`, `track ip_dst`, or `track ip_pair`).
+ `tag:host`.
+ Thresholding.
+ IKEv2 protocol.
+ IP-in-IP protocol.
+ HTTP/2 overloading.
+ Application Layer drop established default rules are incompatible with a session-holding configuration. You can read more at [Managing evaluation order for Suricata compatible rules in AWS Network Firewall.](https://docs.aws.amazon.com/network-firewall/latest/developerguide/suricata-rule-evaluation-order.html)

## Suricata features that Network Firewall supports with caveats
<a name="suricata-supported-with-caveats"></a>

The following Suricata features have caveats for use with Network Firewall:
+ If you want a rule group to use settings for `HOME_NET` and `EXTERNAL_NET` that are different from those that are set for the firewall policy, you must explicitly set both of these variables. 
  + In a firewall policy's variables, you can set a custom value for `HOME_NET`. The default `HOME_NET` setting is the CIDR of the inspection VPC. The policy's `EXTERNAL_NET` setting is always the negation of the policy's `HOME_NET` setting. For example, if the `HOME_NET` is `11.0.0.0`, the `EXTERNAL_NET` is set to `!11.0.0.0`.
  + In a rule group's variables, you can set custom values for both `HOME_NET` and `EXTERNAL_NET`. If you explicitly set rule group variables, those are used. Otherwise, rule group variables inherit their settings from the corresponding policy variables. 

    This means that, if you don't specify the rule group's `EXTERNAL_NET`, it inherits the setting from the policy's `EXTERNAL_NET` setting, regardless of the value of the rule group's `HOME_NET` setting. 

    For example, say you set the rule group's `HOME_NET` to `10.0.0.0`, and the firewall policy's `HOME_NET` to `11.0.0.0`. If you don't set the rule group's `EXTERNAL_NET`, then Network Firewall sets it to `!11.0.0.0`, based on the policy's `HOME_NET` setting. 
+ The AWS Network Firewall stateful inspection engine supports inspecting inner packets for tunneling protocols such as Generic Routing Encapsulation (GRE). If you want to block the tunneled traffic, you can write rules against the tunnel layer itself or against the inner packet. Due to the service inspecting the different layers, you might see flows and alerts for the packets within the tunnel.
+ To create a rule that requires a variable, you must specify the variable in the rule group. Without the required variables, the rule group isn't valid. For an example of a rule group that's configured with variables, see [Stateful rules examples: rule variables](suricata-examples.md#suricata-example-rule-with-variables).
+ In payload keywords, the `pcre` keyword is only allowed with `content`, `tls.sni`, `http.host`, and `dns.query` keywords.
+ The `priority` keyword is not supported for rule groups that evaluate rules using strict evaluation order.
+ When matching TLS based rules in a TLS inspection-enabled configuration, alert logs capture http host information and not the SNI upon rule match
+ When you use a stateful rule with a layer 3 or 4 protocol such as IP or TCP, and you don't include any flow state context, for example `"flow:not_established"`, then Suricata treats this rule as an IP-only rule. Suricata only evaluates IP-only rules for the first packet in each direction of the flow. For example, Suricata will process the following rule as an IP-only rule:

  ```
  pass tcp $HOME_NET any -> [10.0.0.0/8] $HTTPS_PORTS (sid: 44444; rev:2;)
  ```

  However, if the destination IP contains a `!`, then Suricata treats this as per the protocol specified in the rule. Suricata will process the following rule as a TCP rule.

  ```
  pass tcp $HOME_NET any -> [!10.0.0.0/16] $HTTPS_PORTS (sid: 44444; rev:2;)
  ```
+ To match HTTP/2 application traffic under a TLS inspection-enabled configuration, add http2 protocol rules to your rule set in addition to your existing HTTP rules. For example, if you used this rule to match HTTP traffic:

  ```
  drop http $HOME_NET any -> $EXTERNAL_NET any (msg:"example rule"; flow:to_server,established; http.host; content:"example.com"; sid:1; rev:1;)
  ```

  You should add an http2 application rule to your ruleset:

  ```
  drop http $HOME_NET any -> $EXTERNAL_NET any (msg:"example rule"; flow:to_server,established; http.host; content:"example.com"; sid:1; rev:1;)
  drop http2 $HOME_NET any -> $EXTERNAL_NET any (msg:"example rule"; flow:to_server,established; http.request_header; content:"authority|3a 20|example.com"; sid:2; rev:1;)
  ```

# Best practices for writing Suricata compatible rules for AWS Network Firewall
<a name="suricata-best-practices"></a>

A stateful rule group is a rule group that uses Suricata compatible intrusion prevention system (IPS) specifications. Suricata is an open source network IPS that includes a standard rule-based language for stateful network traffic inspection. You can enter any stateful rule in Suricata compatible strings. 

When you write your stateful rules, verify the configuration of the firewall policy where you intend to use them, to make sure that all of your rules evaluate as you want them to. For information about how AWS Network Firewall handles network traffic and when it sends it to the stateful engine, see [How AWS Network Firewall filters network traffic](firewall-policy-processing.md). 

For example, many stateful rules rely on seeing a complete bidirectional traffic flow for correct evaluation, such as rules with options like `flow: established`. To use rules like this, you must configure your stateless rules and default actions to ensure forwarding of traffic for both directions to the stateful engine. For information about these action options, see [Defining rule actions in AWS Network Firewall](rule-action.md). 

# Examples of stateful rules for Network Firewall
<a name="suricata-examples"></a>

This section lists examples of Suricata compatible rules that could be used with AWS Network Firewall. 

**Note**  
Examples are not intended to be used in your Network Firewall configuration exactly as they are listed.  
The examples provide general information and sample rule specifications for common use cases. Before using any rule from these examples or elsewhere, test and adjust it carefully to be sure that it fits your needs. It's your responsibility to ensure that each rule that you use is suited to your specific use case and functioning the way that you want it to. 

## Stateful rules examples: allow traffic
<a name="suricata-example-allow-rules"></a>

**Note**  
Before using any example rule, test and adapt it to your needs.

The examples in this section contain examples that allow specified traffic.

**Allow access to any `ssm.` Server Name Indication (SNI) ending with `.amazonaws.com`**  
Allows access to any domain that begins with `ssm.` and ends with `.amazonaws.com` (http://amazonaws.com/).

```
pass tls $HOME_NET any -> $EXTERNAL_NET any (ssl_state:client_hello; tls.sni; content:"ssm."; startswith; content:".amazonaws.com"; endswith; nocase; flow: to_server; sid:202308311;)
```

**JA3 hash**  
This rule allows outbound access using a specific JA3 hash

```
pass tls $HOME_NET any -> $EXTERNAL_NET any (msg:"Only allow Curl 7.79.1 JA3"; ja3.hash; content:"27e9c7cc45ae47dc50f51400db8a4099"; sid:12820009;)
```

**Outbound requests to `checkip.amazonaws.com`**  
These rules only allow outbound requests to the SNI `checkip.amazonaws.com` (http://checkip.amazonaws.com/) if the server certificate issuer is also Amazon. Requires that your firewall policy uses strict order rule evaluation order.

```
alert tls $HOME_NET any -> $EXTERNAL_NET 443 (ssl_state:client_hello; tls.sni; content:"checkip.amazonaws.com"; endswith; nocase; xbits:set, allowed_sni_destination_ips, track ip_dst, expire 3600; noalert; sid:238745;)
pass tcp $HOME_NET any -> $EXTERNAL_NET 443 (xbits:isset, allowed_sni_destination_ips, track ip_dst; flow: stateless; sid:89207006;)
pass tls $EXTERNAL_NET 443 -> $HOME_NET any (tls.cert_issuer; content:"Amazon"; msg:"Pass rules do not alert"; xbits:isset, allowed_sni_destination_ips, track ip_src; sid:29822;)
reject tls $EXTERNAL_NET 443 -> $HOME_NET any (tls.cert_issuer; content:"="; nocase; msg:"Block all other cert issuers not allowed by sid:29822"; sid:897972;)
```

**Outbound SSH/SFTP servers with `AWS_SFTP` banner**  
These rules only allow outbound access to SSH/SFTP servers that have a banner that includes `AWS_SFTP`, which is the banner for AWS Transfer Family servers. To check for a different banner, replace `AWS_SFTP` with the banner you want to check for.

```
pass tcp $HOME_NET any -> $EXTERNAL_NET 22 (flow:stateless; sid:2221382;)
pass ssh $EXTERNAL_NET 22 -> $HOME_NET any (ssh.software; content:"AWS_SFTP"; flow:from_server; sid:217872;)
drop ssh $EXTERNAL_NET 22 -> $HOME_NET any (ssh.software; content:!"@"; pcre:"/[a-z]/i"; msg:"Block unauthorized SFTP/SSH."; flow: from_server; sid:999217872;)
```

**Send DNS query including `.amazonaws.com` to external DNS servers**  
This rule allows any DNS query for domain names ending in `.amazonaws.com` (http://amazonaws.com/) to be sent to external DNS servers.

```
pass dns $HOME_NET any -> $EXTERNAL_NET any (dns.query; dotprefix; content:".amazonaws.com"; endswith; nocase; msg:"Pass rules do not alert"; sid:118947;)
```

## Stateful rules examples: block traffic
<a name="suricata-example-block-rules"></a>

**Note**  
Before using any example rule, test and adapt it to your needs.

The examples in this section contain examples that block specified traffic.

**Connections using TLS versions 1.0 or 1.1**  
This rule blocks connections using TLS version 1.0 or 1.1.

```
reject tls any any -> any any (msg:"TLS 1.0 or 1.1"; ssl_version:tls1.0,tls1.1; sid:2023070518;)
```

**Multiple CIDR ranges**  
This rule blocks outbound access to multiple CIDR ranges in a single rule.

```
drop ip $HOME_NET any-> [10.10.0.0/16,10.11.0.0/16,10.12.0.0/16] (msg:"Block traffic to multiple CIDRs"; sid:278970;)
```

**Multiple SNIs**  
This rule blocks multiple SNIs with a single rule.

```
reject tls $HOME_NET any -> $EXTERNAL_NET any (ssl_state:client_hello; tls.sni; pcre:"/(example1\.com|example2\.com)$/i"; flow: to_server; msg:"Domain blocked"; sid:1457;)
```

**Multiple high-risk destination outbound ports**  
This rule blocks multiple high-risk destination outbound ports in a single rule.

```
drop ip $HOME_NET any -> $EXTERNAL_NET [1389,53,4444,445,135,139,389,3389] (msg:"Deny List High Risk Destination Ports"; sid:278670;)
```

**Outbound HTTP HOST**  
This rule blocks outbound HTTP connections that have an IP address in the HTTP `HOST` header.

```
reject http $HOME_NET any -> $EXTERNAL_NET any (http.host; content:"."; pcre:"/^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/"; msg:"IP in HTTP HOST Header (direct to IP, likely no DNS resolution first)"; flow:to_server; sid:1239847;)
```

**Outbound TLS with IP in SNI**  
This rule blocks outbound TLS connections with an IP address in the SNI.

```
reject tls $HOME_NET any -> $EXTERNAL_NET any (ssl_state:client_hello; tls.sni; content:"."; pcre:"/^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/"; msg:"IP in TLS SNI (direct to IP, likely no DNS resolution first)"; flow:to_server; sid:1239848;)
```

**Any IP protocols other than TCP, UDP, and ICMP**  
This rule silently blocks any IP protocols other than TCP, UDP, and ICMP.

```
drop ip any any-> any any (noalert; ip_proto:!TCP; ip_proto:!UDP; ip_proto:!ICMP; sid:21801620;)
```

**SSH non-standard ports**  
This rule blocks the use of the SSH protocol on non-standard ports.

```
reject ssh $HOME_NET any -> $EXTERNAL_NET !22 (msg:"Block use of SSH protocol on non-standard port"; flow: to_server; sid:2171010;)
```

**TCP/22 servers non-SSH**  
This rule blocks the use of TCP/22 servers that aren't using the SSH protocol.

```
reject tcp $HOME_NET any -> $EXTERNAL_NET 22 (msg:"Block TCP/22 servers that are not SSH protocol"; flow: to_server; app-layer-protocol:!ssh; sid:2171009;)
```

## Stateful rules examples: log traffic
<a name="suricata-example-logging"></a>

**Note**  
Before using any example rule, test and adapt it to your needs.

The examples in this section demonstrate ways to log traffic. To log traffic, you must configure logging for your firewall. For information about logging Network Firewall traffic, see [Logging and monitoring in AWS Network Firewall](logging-monitoring.md).

**Log traffic direction in default-deny policy**  
Can be used at the end of a default-deny policy to accurately log the direction of denied traffic. These rules help you to make it clear in the logs who the client is and who the server is in the connection.

```
reject tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"Default Egress TCP block to server"; flow:to_server; sid:202308171;)
drop udp $HOME_NET any -> $EXTERNAL_NET any (msg:"Default Egress UDP block";sid:202308172;)
drop icmp $HOME_NET any -> $EXTERNAL_NET any (msg:"Default Egress ICMP block";sid:202308177;)
drop tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"Default Ingress block to server"; flow:to_server; sid:20230813;)
drop udp $EXTERNAL_NET any -> $HOME_NET any (msg:"Default Ingress UDP block"; sid:202308174;)
drop icmp $EXTERNAL_NET any -> $HOME_NET any (msg:"Default Ingress ICMP block"; sid:202308179;)
```

**Log traffic to an allowed SNI**  
The `alert` keyword can be used in the pass rule to generate alert logs for all matches. This rule logs all passed traffic to an allowed SNI.

```
pass tls $HOME_NET any -> $EXTERNAL_NET any (ssl_state:client_hello; tls.sni; content:".example.com"; dotprefix; endswith; nocase; alert; sid:202307052;)
```

## Stateful rules examples: rule variables
<a name="suricata-example-rule-with-variables"></a>

**Note**  
Before using any example rule, test and adapt it to your needs.

The following JSON defines an example Suricata compatible rule group that uses the variables `HTTP_SERVERS` and `HTTP_PORTS`, with the variable definitions provided in the rule group declaration. 

```
{
"RuleVariables": {
    "IPSets": {
        "HTTP_SERVERS": {
            "Definition": [
                "10.0.2.0/24",
                "10.0.1.19"
            ]
        }
    },
    "PortSets": {
        "HTTP_PORTS": {
            "Definition": ["80", "8080"]
        }
    }
},
"RulesSource": {
    "RulesString": "alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:\".htpasswd access attempt\"; flow:to_server,established; content:\".htpasswd\"; nocase; sid:210503; rev:1;)"
}
}
```

The variable `EXTERNAL_NET` is a Suricata standard variable that represents the traffic destination. For more Suricata-specific information, see the [Suricata documentation](https://docs.suricata.io/en/suricata-7.0.8/).

## Stateful rules examples: IP set reference
<a name="suricata-example-rule-with-ip-set-reference"></a>

**Note**  
Before using any example rule, test and adapt it to your needs.

To reference a prefix list in your rule group, specify a IP set variable name and associate it with the prefix list's Amazon Resource Name (ARN). Then, specify the variable in one or more of your rules, prefacing the variable with `@`, such as `@IP_Set_Variable`. The variable represents the IPv4 prefix list that you are referencing. For more information about using IP set references, see [Referencing Amazon VPC prefix lists](rule-groups-ip-set-references.md#rule-groups-referencing-prefix-lists).

The following example shows a Suricata compatible rule that uses an IP set reference variable `@BETA` as the source port in `RulesString`. To use an IP set reference in your rule, you must use an `@` in front of the IP set variable name, such as `@My_IP_set_variable_name`.

```
{
   "RuleVariables":{
      "IPSets":{
         "HTTP_SERVERS":{
            "Definition":[
               "10.0.2.0/24",
               "10.0.1.19"
            ]
         }
      },
      "PortSets":{
         "HTTP_PORTS":{
            "Definition":[
               "80",
               "8080"
            ]
         }
      }
   },
   "ReferenceSets":{
      "IPSetReferences":{
         "BETA":{
            "ReferenceArn":"arn:aws:ec2:us-east-1:555555555555:prefix-list/pl-1111111111111111111_beta"
         }
      }
   },
   "RulesSource":{
      "RulesString":"drop tcp @BETA any -> any any (sid:1;)"
   }
}
```

## Stateful rules examples: Geographic IP filter
<a name="suricata-example-rule-with-geo-ip-filter"></a>

**Note**  
Before using any example rule, test and adapt it to your needs.

For information about Geographic IP filtering in Network Firewall, see [Geographic IP filtering in Suricata compatible AWS Network Firewall rule groups](rule-groups-geo-ip-filtering.md).

The following shows an example Suricata rule string that generates an alert for traffic to or from Russia: 

```
alert ip any any -> any any (msg:"Geographic IP is from RU, Russia"; geoip:any,RU; sid:55555555; rev:1;)
```

The following shows an example standard stateful rule group that drops traffic unless it originates from the United States or the United Kingdom: 

```
{
    "RulesSource": {
      "StatefulRules": [
        {
          "Action": "DROP",
          "Header": {
            "DestinationPort": "ANY",
            "Direction": "FORWARD",
            "Destination": "ANY",
            "Source": "ANY",
            "SourcePort": "ANY",
            "Protocol": "IP"
          },
          "RuleOptions": [
            {
              "Settings": [
                "1"
              ],
              "Keyword": "sid"
            },
            {
              "Settings": [
                "src,!US,UK"
              ],
              "Keyword": "geoip"
            }
          ]
        }
      ]
    },
    "StatefulRuleOptions": {
       "RuleOrder": "STRICT_ORDER"
     }
 }
```

## Stateful rules examples: URL/Domain Category filter
<a name="suricata-example-rule-with-url-filter"></a>

**Note**  
Before using any example rule, test and adapt it to your needs.

For information about URL and Domain Category filtering in Network Firewall, see [URL and Domain Category Filtering in Suricata compatible AWS Network Firewall rule groups](rule-groups-url-filtering.md).

aws\$1url\$1category evaluates complete URLs (with TLS inspection) and domains, while aws\$1domain\$1category evaluates only domain information from TLS SNI or HTTP host headers.

The following shows an example Suricata rule string that generates an alert for traffic categorized as malicious:

```
alert http any any -> any any (msg:"URL Category is Malicious"; aws_url_category:Malicious; sid:55555555; rev:1;)
```

The following shows an example that blocks traffic categorized under gambling and social networking categories:

```
drop http any any -> any any (msg:"Block gambling and social sites"; aws_url_category:Gambling,Social Networking; sid:55555556; rev:1;)
```

The following shows an example standard stateful rule group that drops traffic to malware and phishing sites using `aws_url_category`: 

```
{
    "RulesSource": {
      "StatefulRules": [
        {
          "Action": "DROP",
          "Header": {
            "DestinationPort": "ANY",
            "Direction": "FORWARD",
            "Destination": "ANY",
            "Source": "ANY",
            "SourcePort": "ANY",
            "Protocol": "HTTP"
          },
          "RuleOptions": [
            {
              "Settings": [
                "1"
              ],
              "Keyword": "sid"
            },
            {
              "Settings": [
                "Malware,Phishing"
              ],
              "Keyword": "aws_url_category"
            }
          ]
        }
      ]
    },
    "StatefulRuleOptions": {
      "RuleOrder": "STRICT_ORDER"
    }
}
```

The following shows an example using domain-level filtering that generates an alert for traffic categorized as cryptocurrency:

```
alert tls any any -> any any (msg:"Domain Category is Cryptocurrency"; aws_domain_category:Cryptocurrency; sid:55555557; rev:1;)
```

The following shows an example standard stateful rule group that drops traffic to malware and phishing sites using `aws_domain_category`:

```
{
    "RulesSource": {
      "StatefulRules": [
        {
          "Action": "DROP",
          "Header": {
            "DestinationPort": "ANY",
            "Direction": "FORWARD",
            "Destination": "ANY",
            "Source": "ANY",
            "SourcePort": "ANY",
            "Protocol": "HTTP"
          },
          "RuleOptions": [
            {
              "Settings": [
                "1"
              ],
              "Keyword": "sid"
            },
            {
              "Settings": [
                "Malware,Phishing"
              ],
              "Keyword": "aws_domain_category"
            }
          ]
        }
      ]
    },
    "StatefulRuleOptions": {
      "RuleOrder": "STRICT_ORDER"
    }
}
```

## Stateful rules examples: manage rule evaluation order
<a name="suricata-example-rule-ordering"></a>

**Note**  
Before using any example rule, test and adapt it to your needs.

The examples in this section demonstrate ways to modify evaluation behavior by modifying rule evaluation order in Suricata compatible rules. Network Firewall recommends using strict order so that you can have control over the way your rules are processed for evaulation. For information about managing rule evaluation order, see [Managing evaluation order for Suricata compatible rules in AWS Network Firewall](suricata-rule-evaluation-order.md).

Allow HTTP traffic to specific domains:

**Default action order**

```
drop tcp $HOME_NET any -> $EXTERNAL_NET 80 (msg:"Drop established TCP:80"; flow: from_client,established; sid:172190; priority:5; rev:1;)
pass http $HOME_NET any -> $EXTERNAL_NET 80 (http.host; dotprefix; content:".example.com"; endswith; msg:"Allowed HTTP domain"; priority:10; sid:172191; rev:1;)
pass tcp $HOME_NET any -> $EXTERNAL_NET 22 (msg:"Allow TCP 22"; sid:172192; rev:1;)
drop tcp $HOME_NET any -> $EXTERNAL_NET !80 (msg:"Drop All non-TCP:80";  sid:172193; priority:2; rev:1;)
```

**Strict order**

```
pass http $HOME_NET any -> $EXTERNAL_NET 80 (http.host; dotprefix; content:".example.com"; endswith; msg:"Allowed HTTP domain"; sid:172191; rev:1;)
pass tcp $HOME_NET any -> $EXTERNAL_NET 22 (msg:"Allow TCP 22"; sid:172192; rev:1;)
```

Allow HTTP traffic to specific domains only:

**Default action order**

```
pass http $HOME_NET any -> $EXTERNAL_NET 80 (http.host; dotprefix; content:".example.com"; endswith; msg:"Allowed HTTP domain"; priority:1; sid:102120; rev:1;)
pass http $HOME_NET any -> $EXTERNAL_NET 80 (http.host; dotprefix; content:".mydomain.test"; endswith; msg:"Allowed HTTP domain"; priority:1; sid:102121; rev:1;)
drop http $HOME_NET any -> $EXTERNAL_NET 80 (msg:"Drop HTTP traffic"; priority:1; sid:102122; rev:1;)
```

**Strict order**

```
pass http $HOME_NET any -> $EXTERNAL_NET 80 (http.host; dotprefix; content:".example.com"; endswith; msg:"Allowed HTTP domain"; sid:102120; rev:1;)
pass http $HOME_NET any -> $EXTERNAL_NET 80 (http.host; dotprefix; content:".mydomain.test"; endswith; msg:"Allowed HTTP domain"; sid:102121; rev:1;)
```

Allow HTTP traffic to specific domains only and deny all other IP traffic:

**Default action order**

```
pass http $HOME_NET any -> $EXTERNAL_NET 80 (http.host; dotprefix; content:".example.com"; endswith; msg:"Allowed HTTP domain"; priority:1; sid:892120; rev:1;)
drop tcp $HOME_NET any -> $EXTERNAL_NET 80 (msg:"Drop established non-HTTP to TCP:80"; flow: from_client,established; sid:892191; priority:5; rev:1;)
drop ip $HOME_NET any <> $EXTERNAL_NET any (msg: "Drop non-TCP traffic."; ip_proto:!TCP;sid:892192; rev:1;)
drop tcp $HOME_NET any -> $EXTERNAL_NET !80 (msg:"Drop All non-TCP:80"; sid:892193; priority:2; rev:1;)
```

**Strict order**

```
pass http $HOME_NET any -> $EXTERNAL_NET 80 (http.host; dotprefix; content:".example.com"; endswith; msg:"Allowed HTTP domain"; sid:892120; rev:1;)
pass tcp $HOME_NET any <> $EXTERNAL_NET 80 (flow:not_established; sid:892191; rev:1;)
```

## Stateful rules examples: domain list rules
<a name="suricata-example-domain-filtering"></a>

**Note**  
Before using any example rule, test and adapt it to your needs.

**Deny list example JSON, rule group creation, and generated Suricata rules**  
The following JSON shows an example rule definition for a Network Firewall domain list rule group that specifies a deny list.

```
{
    "RulesSource": {
        "RulesSourceList": {
            "Targets": [
                "evil.com"
            ],
            "TargetTypes": [
                 "TLS_SNI",
                 "HTTP_HOST"
             ],
             "GeneratedRulesType": "DENYLIST"
        }
    }
}
```

To use the Network Firewall rule specification, we save the JSON to a local file `domainblock.example.json`, and then create the rule group in the following CLI command: 

```
aws network-firewall create-rule-group --rule-group-name "RuleGroupName" --type STATEFUL --rule-group file://domainblock.example.json --capacity 1000
```

The following Suricata rules listing shows the rules that Network Firewall creates for the above deny list specification.

```
drop tls $HOME_NET any -> $EXTERNAL_NET any (ssl_state:client_hello; tls.sni; content:"evil.com"; startswith; nocase; endswith; msg:"matching TLS denylisted FQDNs"; priority:1; flow:to_server, established; sid:1; rev:1;)
drop http $HOME_NET any -> $EXTERNAL_NET any (http.host; content:"evil.com"; startswith; endswith; msg:"matching HTTP denylisted FQDNs"; priority:1; flow:to_server, established; sid:2; rev:1;)
```

**HTTP allow list example JSON and generated Suricata rules**  
The following JSON shows an example rule definition for a Network Firewall domain list rule group that specifies an HTTP allow list. The `.` before the domain name in `.amazon.com` is the wildcard indicator in Suricata.

```
{
    "RulesSource": {
        "RulesSourceList": {
            "Targets": [
                ".amazon.com",
                "example.com"
            ],
            "TargetTypes": [
                "HTTP_HOST"
            ],
            "GeneratedRulesType": "ALLOWLIST"
        }
    }
}
```

The following Suricata rules listing shows the rules that Network Firewall creates for the above allow list specification.

```
pass http $HOME_NET any -> $EXTERNAL_NET any (http.host; dotprefix; content:".amazon.com"; endswith; msg:"matching HTTP allowlisted FQDNs"; priority:1; flow:to_server, established; sid:1; rev:1;)
pass http $HOME_NET any -> $EXTERNAL_NET any (http.host; content:"example.com"; startswith; endswith; msg:"matching HTTP allowlisted FQDNs"; priority:1; flow:to_server, established; sid:2; rev:1;)
drop http $HOME_NET any -> $EXTERNAL_NET any (http.header_names; content:"|0d 0a|"; startswith; msg:"not matching any HTTP allowlisted FQDNs"; priority:1; flow:to_server, established; sid:3; rev:1;)
```

**TLS allow list example JSON and generated Suricata rules**  
The following JSON shows an example rule definition for a Network Firewall domain list rule group that specifies a TLS allow list.

```
{
    "RulesSource": {
        "RulesSourceList": {
            "Targets": [
                ".amazon.com",
                "example.com"
            ],
            "TargetTypes": [
                "TLS_SNI"
            ],
            "GeneratedRulesType": "ALLOWLIST"
        }
    }
}
```

The following Suricata rules listing shows the rules that Network Firewall creates for the above allow list specification.

```
pass tls $HOME_NET any -> $EXTERNAL_NET any (ssl_state:client_hello; tls.sni; dotprefix; content:".amazon.com"; nocase; endswith; msg:"matching TLS allowlisted FQDNs"; priority:1; flow:to_server, established; sid:1; rev:1;)
pass tls $HOME_NET any -> $EXTERNAL_NET any (ssl_state:client_hello; tls.sni; content:"example.com"; startswith; nocase; endswith; msg:"matching TLS allowlisted FQDNs"; priority:1; flow:to_server, established; sid:2; rev:1;)
drop tls $HOME_NET any -> $EXTERNAL_NET any (msg:"not matching any TLS allowlisted FQDNs"; priority:1; ssl_state:client_hello; flow:to_server, established; sid:3; rev:1;)
```

**Block traffic from `$EXTERNAL_NET` to `$HOME_NET`, allow outbound domain filtering**  
These rules block all unsolicited traffic from `$EXTERNAL_NET` to `$HOME_NET` while still allowing outbound domain filtering.

```
reject tls any any -> any any (msg:"Vulnerable versions of TLS"; ssl_version:tls1.0,tls1.1; sid:2023070518;)
```

## Stateful rules examples: standard stateful rule groups
<a name="suricata-example-basic"></a>

**Note**  
Before using any example rule, test and adapt it to your needs.

The following JSON shows an example rule definition for a Network Firewall basic stateful rule group. 

```
{
    "RulesSource": {
        "StatefulRules": [
          {
            "Action": "DROP",
            "Header": {
                "Protocol": "HTTP",
                "Source": "$HOME_NET",
                "SourcePort": "ANY",
                "Direction": "ANY",
                "Destination": "$EXTERNAL_NET",
                "DestinationPort": "ANY"
            },
            "RuleOptions": [ {
                    "Keyword": "msg",
                    "Settings": [ "\"this is a stateful drop rule\""
                    ]
                },
                {
                    "Keyword": "sid",
                    "Settings": [ "1234"
                    ]
                }
            ]
        }
      ]
    }
}
```

The following Suricata rules listing shows the rules that Network Firewall generates for the above deny list specification.

```
drop http $HOME_NET ANY <> $EXTERNAL_NET ANY (msg:this is a stateful drop rule; sid:1234;)
```

## Stateful rules example: allow traffic to a domain using its SNI
<a name="suricata-example-allow-one-domain-strict"></a>

**Note**  
Before using any example rule, test and adapt it to your needs.

The following set of rules will allow traffic to a domain using its SNI, while blocking traffic to all other domains in a strict order action policy.

```
# Drop all established to_server traffic (even TLS) from $HOME_NET to $EXTERNAL_NET 
drop tcp $HOME_NET any -> $EXTERNAL_NET any (flow: to_server, established; sid:1;)

# This rule does not allow the traffic because it is already dropped by sid:1, but it does keep the dropped traffic from touching any other rules in the ruleset
pass tcp $HOME_NET any -> $EXTERNAL_NET any (flow: to_server, established; sid:11;)

# Allow all TLS from anywhere to anywhere if it's SNI is example.com
pass tls $HOME_NET any -> $EXTERNAL_NET any (ssl_state:client_hello; tls.sni; content:"example.com"; dotprefix; nocase; flow: to_server, established; sid:2;)
```

## Stateful rules example: filter domains on http2
<a name="suricata-example-http2-domain-filter"></a>

**Note**  
Before using any example rule, test and adapt it to your needs.

The following set of rules will allow http2 traffic to `https://example.com` and block all other http2 traffic.

```
# Pass the domain with an http2 based rule
pass http2 $HOME_NET any -> $EXTERNAL_NET any (http.request_header; content:"authority|3a 20|example.com"; sid:1; rev:1;)

# Reject traffic for non-allowed TCP except http2
reject tcp $HOME_NET any -> $EXTERNAL_NET any (app-layer-protocol:!http2; flow:to_server, established; sid:2; rev:1;)

# Drop all other http2 decrypted traffic
drop http2 $HOME_NET any -> $EXTERNAL_NET any (flow:established, to_server; http2.header_name; content:"authority"; sid:3; rev:1;)
```