Question: How do I configure Network Firewall standard rule groups and domain list rule group rules together?

I want to configure AWS Network Firewall standard rule group rules and domain list rule group rules to work together to control traffic as expected.

Short descriptionYou can configure standard rule group rules to drop established TCP traffic. You can then configure domain list rule group rules to allow the TCP (TLS) flows sent to allowed domains from the domain list rule group. You do this by configuring a domain list rule group and standard rule group rules with a "flow" keyword.Note: The Amazon Virtual Private Cloud (Amazon VPC) console displays only previously configured rule options. It doesn't allow you to add rule options. For more information, see Standard stateful rule groups in AWS Network Firewall.You can use AWS CloudFormation or an API to specify rule options for your standard rule group rules. AWS Command Line Interface (AWS CLI) is used for the examples in this article:Note: If you receive errors when running AWS CLI commands, make sure that you're using the most recent version of the AWS CLI.

ResolutionPrerequisitesBefore you configure your Network Firewall rules, review the following information:This article presents a method of configuring standard rule group rules that allows for entry of rule options. In this example, adding rule options to a standard rule group rule allows it to work with a domain list rule group. This allows you to better control your traffic.This article uses one of the distributed deployment models. This model protects traffic between a workload public subnet with a client Amazon Elastic Compute Cloud (Amazon EC2) instance and an internet gateway. The firewall policy rule order is set to default action order.The Amazon EC2 instance is allowed to send traffic on TCP port 443 in VPC Security Group and network ACL.The firewall rules used in the article are examples to refer to. You must make sure that the rules you configure for your firewall are suited to your specific need and work as expected.Note: In the code examples in this article, ellipses (...) have been used to shorten outputs.Common configuration of domain list rule group and standard rule group without flow keywordWhen you configure a domain list rule group and standard rule group, your configuration can be similar to the one detailed in this example. If you create a domain list rule group and standard rule group, then you must use a flow keyword. If you don't use a flow keyword, then you might encounter problems such as the one detailed in this example.In this example, the Amazon VPC console is used to create a domain list rule group. The rule allows HTTPS traffic to example.com.Domain name source: example.comSource IPs type: DefaultProtocol: HTTPsAction: AllowNote: A domain list rule group with the action set to Allow generates another rule. The rule is set to deny traffic of the specified protocol type that doesn't match the domain specifications. For more information, see Domain filtering.Using the Amazon VPC console to create a common configuration of a standard rule group rule produces output similar to the following table:ProtocolSourceDestinationSource portDestination portDirectionActionTCPAnyAnyAnyAnyForwardDropWhen sending a request to an allowed domain to test your rule configuration, the traffic is blocked and you receive a "connection timed out" error:$ curl -kv -so /dev/null https://example.com* Trying 93.184.216.34:443...* connect to 93.184.216.34 port 443 failed: Connection timed out* Failed to connect to example.com port 443 after 129180 ms: Connection timed out* Closing connection 0The configuration causes all TCP traffic to be dropped and for the connection to time out. This includes blocking TCP-based traffic to the allowed domain example.com.The domain list rule group rule to allow example.com over HTTPS fails because the TCP protocol is the first protocol to appear in the initial flow. The flow starts with the lower-layer TCP handshake and the deny rule is evaluated. However, there is still no TLS protocol to match, and so the drop rule matches. This causes all traffic to example.com to drop.Note: You can configure logging levels for your firewall's stateful engine, allowing you to access detailed information about filtered traffic. For more information, see Logging network traffic from AWS Network Firewall.Domain list rule group and standard rule group rule with flow keywordYou can use the Network Firewall describe-rule-group and update-rule-group commands to update your standard rule group rules to include an additional flow keyword.1.    Run the describe-rule-group command against the original Stateful rule group object. You need the UpdateToken value in order to run the update-rule-group command.Note: Part of the output from the following command is used as a JSON template for other adjustments later.$ aws network-firewall describe-rule-group --rule-group-arn "arn:aws:network-firewall:us-east-1:XXXXXXXX0575:stateful-rulegroup/stateful-rg-5-tuple" --output json{    "UpdateToken": "40b87af5-a20c-4f8c-8afd-6777c81add3c",    (...)        "RulesSource": {            "StatefulRules": [{                "Action": "DROP",                "Header": {                    "Protocol": "TCP",                    "Source": "Any",                    "SourcePort": "Any",                    "Direction": "FORWARD",                    "Destination": "Any",                    "DestinationPort": "Any"                },                "RuleOptions": [{                    "Keyword": "sid",                    "Settings": [                        "5"                    ]                }]            }]        }    (...)}2.    Create a JSON rule file with a modified rule configuration. Run a command similar to the following to verify JSON rule file content:$ cat tcp-drop-rule-updated.json{  "RulesSource": {    "StatefulRules": [      {        "Action": "DROP",        "Header": {          "Direction": "FORWARD",          "Protocol": "TCP",          "Destination": "Any",          "Source": "Any",          "DestinationPort": "Any",          "SourcePort": "Any"        },        "RuleOptions": [          {            "Keyword": "sid",            "Settings": [              "5"            ]          },          {            "Keyword": "flow",            "Settings": [              "established, to_server"            ]          }        ]      }    ]  }}In this example, the flow keyword allows the TCP handshake to complete before evaluating the TCP drop rule when sending a request to example.com. After this, the rule default action order takes precedence. The domain list allow HTTPS rule for example.com matches, allowing the rest of the traffic through for that flow. Any traffic to not allowed domains is blocked, as well as any other established TCP traffic.3.    Run the update-rule-group command using the UpdateToken value and JSON rule file to update standard rule group:$ aws network-firewall update-rule-group --rule-group-arn "arn:aws:network-firewall:us-east-1:XXXXXXXX0575:stateful-rulegroup/stateful-rg-5-tuple" --update-token 40b87af5-a20c-4f8c-8afd-6777c81add3c --rule-group file://tcp-drop-rule-updated.json --output jsonThe result looks similar to this output:{    "UpdateToken": "bf8fe6d4-f13e-406c-90c1-9e3bad2118a7",    "RuleGroupResponse": {(...)},        "LastModifiedTime": "2023-02-07T14:12:14.993000+11:00"    }}4.    Run the describe-rule-group command to verify the changes to the Stateful rule group:$ aws network-firewall describe-rule-group --rule-group-arn "arn:aws:network-firewall:us-east-1:XXXXXXXX0575:stateful-rulegroup/stateful-rg-5-tuple" --output jsonThe output looks similar to the following message:{(...)        "RulesSource": {            "StatefulRules": [                {                    "Action": "DROP",                    "Header": {                        "Protocol": "TCP",                        "Source": "Any",                        (...)                    },                    "RuleOptions": [                        {                            "Keyword": "sid",                            "Settings": [                                "5"                            ]                        },                        {                            "Keyword": "flow",                            "Settings": [                                "established, to_server"                           ]           (...)        }    },    "RuleGroupResponse": {(...)        },        "LastModifiedTime": "2023-02-07T14:12:14.993000+11:00"    }}Note: In the preceding example, "established, to_server" reflects the change from the update-rule-group command.5.    Verify that both the domain list rule group and standard rule group filter traffic correctly:$ curl -kv -so /dev/null https://example.com*   Trying  93.184.216.34 :443...* Connected to example.com ( 93.184.216.34 ) port 443 (#0)(...)> GET / HTTP/1.1> Host: example.com(...)< HTTP/1.1 200 OK(...)In the previous example, the output shows that HTTPS traffic to the allowed domain example.com succeeds, as configured.In this next example, HTTPS traffic to domains that aren't allowed is blocked, as expected:$ curl -m 5 -kv -so /dev/null https://www.amazon.com*   Trying  93.184.216.34 :443...* Connected to www.amazon.com ( 93.184.216.34 ) port 443 (#0)(...)* TLSv1.2 (OUT), TLS handshake, Client hello (1):(...)* Operation timed out after 5000 milliseconds with 0 out of 0 bytes received* Closing connection 0Other types of TCP traffic are also blocked based off the configuration:$ aws s3 ls --cli-read-timeout 30 --debug(...)Read timeout on endpoint URL: "https://s3.amazonaws.com/"Related informationHands-on walkthrough of the AWS Network Firewall flexible rules engine – Part 1