AWS Network Firewall を利用して特定のドメインのアクセスを許可または拒否する

# ステートフルドメインリスト

Network Firewall を利用して特定のドメインのアクセスを許可または拒否するには、ステートフルドメインリストまたは Suricata 対応の IPS ルールで対応可能かと思いますが、今回は ステートフルドメインリストを利用してみたいと思います。

なお、ステートフルドメイン名の検査は以下を見て行われるようである。

- **HTTP**
  - HTTP ホストヘッダー
- **HTTPS**
  - TLS ハンドシェイクの Server Name Indication (SNI) におけるserver_name


# 環境

環境は下記の方の CloudFormationテンプレートを利用させてもらいました。

https://zenn.dev/osprey/articles/networkfirewall-is-not-for-domainbase-restriction

なお、ログも確認してみたかったので、AWSコンソールから、CloudWatch log group にログを配信しておくように設定を追加しました。

https://docs.aws.amazon.com/ja_jp/network-firewall/latest/developerguide/firewall-logging-destinations.html


# アクションの順序と厳密な順序

https://docs.aws.amazon.com/ja_jp/network-firewall/latest/developerguide/suricata-rule-evaluation-order.html#suricata-strict-rule-evaluation-order.html

- **アクションの順序**
  - パスアクションを含むルールが最初に処理され、その後にドロップ、拒否、アラートアクションが続きます。

- **厳密な評価順序**
  - ルールは、最初のルールから、定義された順序で処理されます。

## アクションの順序

まず、CloudFormationテンプレートをデプロイするとアクションの順序でデプロイされます。

下記の通り、VPC内の 10.0.0.0/16 からは www.yahoo.co.jp もしくは .ap-northeast-1.amazonaws.com へのアクセスのみ許可し、それ以外の通信は拒否するということになります。（ホワイトリスト形式）

![スクリーンショット 2023-11-16 15.16.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/cd27ef3d-3cbf-9623-dfb6-9fe31e1acb28.png)

こちらは期待通り、 https://www.yahoo.co.jp への通信が可能であることが確認できました。

```json
curl -v https://www.yahoo.co.jp

{
    "firewall_name": "NetworkFirwallTestXYZ",
    "availability_zone": "ap-northeast-1a",
    "event_timestamp": "1700121275",
    "event": {
        "tcp": {
            "tcp_flags": "1b",
            "syn": true,
            "fin": true,
            "psh": true,
            "ack": true
        },
        "app_proto": "tls",
        "src_ip": "10.0.1.254",
        "src_port": 46036,
        "netflow": {
            "pkts": 20,
            "bytes": 1863,
            "start": "2023-11-16T07:53:10.841142+0000",
            "end": "2023-11-16T07:53:10.909158+0000",
            "age": 0,
            "min_ttl": 63,
            "max_ttl": 63
        },
        "event_type": "netflow",
        "flow_id": 718044618216886,
        "dest_ip": "182.22.24.252",
        "proto": "TCP",
        "dest_port": 443,
        "timestamp": "2023-11-16T07:54:35.629281+0000"
    }
}

{
    "firewall_name": "NetworkFirwallTestXYZ",
    "availability_zone": "ap-northeast-1a",
    "event_timestamp": "1700121275",
    "event": {
        "tcp": {
            "tcp_flags": "1f",
            "syn": true,
            "fin": true,
            "rst": true,
            "psh": true,
            "ack": true
        },
        "app_proto": "tls",
        "src_ip": "182.22.24.252",
        "src_port": 443,
        "netflow": {
            "pkts": 38,
            "bytes": 42781,
            "start": "2023-11-16T07:53:10.841142+0000",
            "end": "2023-11-16T07:53:10.909158+0000",
            "age": 0,
            "min_ttl": 52,
            "max_ttl": 246
        },
        "event_type": "netflow",
        "flow_id": 718044618216886,
        "dest_ip": "10.0.1.254",
        "proto": "TCP",
        "dest_port": 46036,
        "timestamp": "2023-11-16T07:54:35.629316+0000"
    }
}
```

こちらも期待通り、 https://www.yahoo.co.jp 以外への通信は、"not matching any TLS allowlisted FQDNs"という理由で、"blocked"され、"alert"として上がっていることが確認できました。

```json
curl -v https://www.google.co.jp
{
    "firewall_name": "NetworkFirwallTestXYZ",
    "availability_zone": "ap-northeast-1a",
    "event_timestamp": "1700116541",
    "event": {
        "app_proto": "tls",
        "src_ip": "10.0.1.254",
        "src_port": 51102,
        "event_type": "alert",
        "alert": {
            "severity": 1,
            "signature_id": 3,
            "rev": 1,
            "signature": "not matching any TLS allowlisted FQDNs",
            "action": "blocked",
            "category": ""
        },
        "flow_id": 1890905392752842,
        "dest_ip": "172.217.175.3",
        "proto": "TCP",
        "tls": {
            "sni": "www.google.co.jp",
            "version": "UNDETERMINED",
            "ja3": {},
            "ja3s": {}
        },
        "dest_port": 443,
        "timestamp": "2023-11-16T06:35:41.537802+0000"
    }
}
```

次に、`GeneratedRulesType`を`DENYLIST`にし、下記の通り、VPC内の 10.0.0.0/16 からは www.yahoo.co.jp へのアクセスのみ拒否し、それ以外の通信は許可するように CloudFormationテンプレートを変更しましょう。（ブラックリスト形式）
なお、.ap-northeast-1.amazonaws.com はセッションマネージャーで接続できなくなってしまうのでコメンアウトにしておきます。
ブラックリスト形式

```yaml
        RulesSource:
          RulesSourceList:
            Targets:
              - "www.yahoo.co.jp"
              # - ".ap-northeast-1.amazonaws.com"
            TargetTypes:
              - "TLS_SNI"
              - "HTTP_HOST"
            GeneratedRulesType: "DENYLIST"
```

![スクリーンショット 2023-11-16 17.10.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/700434ff-ab72-f034-5813-866d70daffca.png)

こちらは期待通り、 https://www.yahoo.co.jp への通信は"matching TLS denylisted FQDNs"という理由で、"blocked"され、"alert"となっていることが確認できました。

```json
curl -v https://www.google.co.jp

{
    "firewall_name": "NetworkFirwallTestXYZ",
    "availability_zone": "ap-northeast-1a",
    "event_timestamp": "1700122951",
    "event": {
        "tx_id": 0,
        "app_proto": "tls",
        "src_ip": "10.0.1.254",
        "src_port": 56346,
        "event_type": "alert",
        "alert": {
            "severity": 1,
            "signature_id": 1,
            "rev": 1,
            "signature": "matching TLS denylisted FQDNs",
            "action": "blocked",
            "category": ""
        },
        "flow_id": 1694041691850110,
        "dest_ip": "182.22.24.124",
        "proto": "TCP",
        "tls": {
            "sni": "www.yahoo.co.jp",
            "version": "UNDETERMINED",
            "ja3": {},
            "ja3s": {}
        },
        "dest_port": 443,
        "timestamp": "2023-11-16T08:22:31.660423+0000"
    }
}
```

こちらも期待通り、 https://www.google.co.jp へのアクセスはアクセス可能であることが確認できました。

```json
curl -v https://www.google.co.jp

{
    "firewall_name": "NetworkFirwallTestXYZ",
    "availability_zone": "ap-northeast-1a",
    "event_timestamp": "1700122941",
    "event": {
        "tcp": {
            "tcp_flags": "1b",
            "syn": true,
            "fin": true,
            "psh": true,
            "ack": true
        },
        "app_proto": "tls",
        "src_ip": "10.0.1.254",
        "src_port": 47938,
        "netflow": {
            "pkts": 27,
            "bytes": 2302,
            "start": "2023-11-16T08:18:18.144463+0000",
            "end": "2023-11-16T08:18:18.292059+0000",
            "age": 0,
            "min_ttl": 63,
            "max_ttl": 63
        },
        "event_type": "netflow",
        "flow_id": 569172560589903,
        "dest_ip": "172.217.175.99",
        "proto": "TCP",
        "dest_port": 443,
        "timestamp": "2023-11-16T08:22:21.095674+0000"
    }
}

{
    "firewall_name": "NetworkFirwallTestXYZ",
    "availability_zone": "ap-northeast-1a",
    "event_timestamp": "1700122941",
    "event": {
        "tcp": {
            "tcp_flags": "1f",
            "syn": true,
            "fin": true,
            "rst": true,
            "psh": true,
            "ack": true
        },
        "app_proto": "tls",
        "src_ip": "172.217.175.99",
        "src_port": 443,
        "netflow": {
            "pkts": 29,
            "bytes": 25922,
            "start": "2023-11-16T08:18:18.144463+0000",
            "end": "2023-11-16T08:18:18.292059+0000",
            "age": 0,
            "min_ttl": 56,
            "max_ttl": 56
        },
        "event_type": "netflow",
        "flow_id": 569172560589903,
        "dest_ip": "10.0.1.254",
        "proto": "TCP",
        "dest_port": 47938,
        "timestamp": "2023-11-16T08:22:21.095773+0000"
    }
}
```


## 厳密な順序

**ステートフルルールの順序は後から変更できない**ので、CloudFormationテンプレートを修正してデプロイしなおします。

`NetworkFirewallPolicy`: 以下の通り書き換えます。
`StatefulRuleGroup`: コメントアウトしてしまいます。
`StatefulRuleGroup2`: 新しく作成します。

```yaml
  NetworkFirewallPolicy:
    Type: AWS::NetworkFirewall::FirewallPolicy
    Properties:
      FirewallPolicyName: NetworkFirewallPolicyTestXYZ
      FirewallPolicy:
        StatelessDefaultActions:
          - 'aws:forward_to_sfe' 
        StatelessFragmentDefaultActions:
          - 'aws:forward_to_sfe'
        StatefulDefaultActions: 
          - 'aws:drop_established'
          - "aws:alert_established"
        StatefulEngineOptions: 
            RuleOrder: 'STRICT_ORDER'
            StreamExceptionPolicy: 'DROP'
        StatefulRuleGroupReferences:
          - ResourceArn: !Ref StatefulRuleGroup2
            Priority: 100
      Tags:
        - Key: Name
          Value: NetworkFirewallPolicy
  # StatefulRuleGroup:
  #   Type: AWS::NetworkFirewall::RuleGroup
  #   Properties:
  #     RuleGroupName: StatefulRuleGroupTestXYZ
  #     Type: STATEFUL
  #     Capacity: 100
  #     RuleGroup:
  #       RuleVariables:
  #         IPSets:
  #           HOME_NET:
  #             Definition:
  #               - "10.0.0.0/16"
  #       RulesSource:
  #         RulesSourceList:
  #           Targets:
  #             - "www.yahoo.co.jp"
  #             - ".ap-northeast-1.amazonaws.com"
  #           TargetTypes:
  #             - "TLS_SNI"
  #             - "HTTP_HOST"
  #           GeneratedRulesType: "ALLOWLIST"
  #     Tags:
  #       - Key: Name
  #         Value: AllowDomainList
  StatefulRuleGroup2:
    Type: AWS::NetworkFirewall::RuleGroup
    Properties:
      RuleGroupName: StatefulRuleGroupTestABC
      Type: STATEFUL
      Capacity: 100
      RuleGroup:
        RuleVariables:
          IPSets:
            HOME_NET:
              Definition:
                - "10.0.0.0/16"
        RulesSource:
          RulesSourceList:
            Targets:
              - "www.yahoo.co.jp"
              - ".ap-northeast-1.amazonaws.com"
            TargetTypes:
              - "TLS_SNI"
              - "HTTP_HOST"
            GeneratedRulesType: "ALLOWLIST"
        StatefulRuleOptions:
          RuleOrder: STRICT_ORDER
      Tags:
        - Key: Name
          Value: AllowDomainList
```

順序が厳密な順序になっただけで後はアクションの順序と同じです。
今回はルールが 1 つしかないので実際は順序も何もあまり関係ありませんが、ルールにマッチしない場合、デフォルトのアクションの動作となり「**確率された接続のパケットをドロップ**」するということになるはずです。
そのため、下記の通り、VPC内の 10.0.0.0/16 からは www.yahoo.co.jp もしくは .ap-northeast-1.amazonaws.com へのアクセスのみ許可し、それ以外の通信はドロップするということになるはずです。
また、アラートとして記録しておきたいため、アラートアクションは「確立済み」にしておきます。
![スクリーンショット 2023-11-17 19.40.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/ab06a658-3f99-1323-77fa-0956c0844ac9.png)
![スクリーンショット 2023-11-18 16.00.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/308db251-8e85-091b-5e90-aa53d7877205.png)

期待通り、https://www.yahoo.co.jp へのアクセスは可能でした。

```json
curl -v https://www.yahoo.co.jp

{
    "firewall_name": "NetworkFirwallTestXYZ",
    "availability_zone": "ap-northeast-1a",
    "event_timestamp": "1700219087",
    "event": {
        "tcp": {
            "tcp_flags": "1b",
            "syn": true,
            "fin": true,
            "psh": true,
            "ack": true
        },
        "app_proto": "tls",
        "src_ip": "10.0.1.238",
        "src_port": 60922,
        "netflow": {
            "pkts": 21,
            "bytes": 1915,
            "start": "2023-11-17T11:01:34.112672+0000",
            "end": "2023-11-17T11:01:34.210978+0000",
            "age": 0,
            "min_ttl": 63,
            "max_ttl": 63
        },
        "event_type": "netflow",
        "flow_id": 1694101666707488,
        "dest_ip": "183.79.217.124",
        "proto": "TCP",
        "dest_port": 443,
        "timestamp": "2023-11-17T11:04:47.499730+0000"
    }
}

{
    "firewall_name": "NetworkFirwallTestXYZ",
    "availability_zone": "ap-northeast-1a",
    "event_timestamp": "1700219087",
    "event": {
        "tcp": {
            "tcp_flags": "1f",
            "syn": true,
            "fin": true,
            "rst": true,
            "psh": true,
            "ack": true
        },
        "app_proto": "tls",
        "src_ip": "183.79.217.124",
        "src_port": 443,
        "netflow": {
            "pkts": 36,
            "bytes": 42760,
            "start": "2023-11-17T11:01:34.112672+0000",
            "end": "2023-11-17T11:01:34.210978+0000",
            "age": 0,
            "min_ttl": 47,
            "max_ttl": 47
        },
        "event_type": "netflow",
        "flow_id": 1694101666707488,
        "dest_ip": "10.0.1.238",
        "proto": "TCP",
        "dest_port": 60922,
        "timestamp": "2023-11-17T11:04:47.499773+0000"
    }
}
```

こちらは期待通り、 https://www.google.co.jp への通信は"aws:alert_established action"で、"blocked"となり、"alert"となっていることが確認できました。

```
curl -v  https://www.google.co.jp

{
    "firewall_name": "NetworkFirwallTestXYZ",
    "availability_zone": "ap-northeast-1a",
    "event_timestamp": "1700291239",
    "event": {
        "app_proto": "tls",
        "src_ip": "10.0.1.241",
        "src_port": 32912,
        "event_type": "alert",
        "alert": {
            "severity": 3,
            "signature_id": 4,
            "rev": 0,
            "signature": "aws:alert_established action",
            "action": "blocked",
            "category": ""
        },
        "flow_id": 143082048128413,
        "dest_ip": "216.58.220.99",
        "proto": "TCP",
        "tls": {
            "sni": "www.google.co.jp",
            "version": "UNDETERMINED",
            "ja3": {},
            "ja3s": {}
        },
        "dest_port": 443,
        "timestamp": "2023-11-18T07:07:19.856035+0000"
    }
}
```

# 参考

https://repost.aws/ja/knowledge-center/network-firewall-configure-domain-rules

https://aws.amazon.com/jp/builders-flash/202310/network-firewall-log-analysis/?awsf.filter-name=*all