AWS Network Firewallを経由して通信できるか気になるな
こんにちは、のんピ(@non____97)です。
皆さんはAWS Network Firewallを経由して通信できるか気になるなと思ったことはありますか? 私はあります。
通信経路のチェックと言えばAmazon VPC Reachability Analyzer(以降Reachability Analyzer)です。
しかし、Reachability AnalyzerはNetwork Firewallを通る経路をチェックすることができませんでした。そのため、通信ができない場合はルートテーブルやNetwork Firewallのメトリクス、ログから原因を調査する必要があります。
今回、Reachability AnalyzerがNetwork Firewall、Gateway Load BalancerとAWS PrivateLinkをサポートしました。
これはありがたいですね。
また、Gateway Load BalancerのターゲットのファイアウォールアプライアンスやNetwork Firewallのルールによって通信がブロックされているかも確認できるようになったようです。
試してみたので紹介します。
いきなりまとめ
- Amazon VPC Reachability Analyzerが以下サービスをサポート
- AWS Network Firewall
- Gateway Load Balancer
- AWS PrivateLink
- Gateway Load BalancerのターゲットのファイアウォールアプライアンスやNetwork Firewallのルールによって通信がブロックされているかも確認
- Reachability AnalyzerはTCP/UDPしかサポートしていない
- HTTPなど上位のレイヤーでルールを定義している場合は、意図した結果とならない
- Network Firewallにおいて、いずれのルールにもマッチしない場合はnetwork-firewall-policy-defaultという設定していないファイアウォールポリシーで評価される
- デフォルトアクションでドロップするようなものを指定している場合は、このファイアウォールポリシーによってドロップされたと表示される
- Network Firewallのルールにおいて、
msg
やrev
はサポートされていないルールオプションとして認識される- これらルールオプションを指定していてもパスの分析結果には影響を与えない
- Network Firewallにおいて、戻りの通信のルートがない場合は到達可能となるが、
UNIDIRECTIONAL_PATH_ANALYSIS_ONLY
と戻りの通信で何かしら不具合があったことが示唆される- 可達のステータスのみで判断するではなく、パス内で表示されるメッセージも確認する必要
検証環境
検証環境は以下の通りです。
ルールグループにはTLS/443を許可するルールと、HTTP/80を拒否するルールを定義しています。
また、ファイアウォールポリシーは厳格(Strict)にしており、デフォルトアクションは何も選択していない状態です。
検証環境はAWS CDKでデプロイします。使用したコードは以下リポジトリに保存しています。
やってみる
TCP/443の通信経路チェック
早速やってみます。
Reachability AnalyzerがTCP/443の通信経路を認識してくれるかチェックします。
まず、VPCエンドポイントがない状態でもEC2インスタンスにSSMセッションマネージャーで接続できることや、EC2インスタンスからHTTPSで通信できることを確認しました。
$ curl -m 5 https://dev.classmethod.jp -I
HTTP/2 200
date: Tue, 28 Mar 2023 02:18:22 GMT
content-type: text/html; charset=utf-8
content-length: 168287
server: nginx/1.22.1
vary: Accept-Encoding
x-amzn-requestid: b5c41faf-0c1f-4cde-9312-29f4961b4880
x-amzn-remapped-content-length: 168287
x-amz-apigw-id: CeErKENDNjMFi-A=
cache-control: max-age=300
etag: "2915f-vD1WK4HW3441WF3fChXfmHeR8uI"
x-powered-by: Express
x-amzn-trace-id: Root=1-64224e46-1055f5985e2d9be633dcf0c4;Sampled=0
via: 1.1 4e4278a2778e72cc34feef6db603088c.cloudfront.net (CloudFront), 1.1 8731d2a1a7d15f67b588bf58f652f9f0.cloudfront.net (CloudFront)
x-amz-cf-pop: HIO52-P1
vary: Accept-Encoding
x-cache: Hit from cloudfront
x-amz-cf-pop: HIO52-P1
x-amz-cf-id: MmbUrYZ5rmCu2CUm4L_OyZw2pOxNaCMvnadOKADxAvEHc1-gV01BQA==
age: 38
expires: Tue, 28 Mar 2023 02:23:22 GMT
strict-transport-security: max-age=31536000; includeSubDomains
accept-ranges: bytes
それではReachability Analyzerのパスを作成します。
送信元をEC2インスタンス、送信先をdev.classmethod.jp
のIPアドレスを指定します。また、送信先ポートは443とします。プロトコルはTLS or HTTPSにしたいところですが、Reachability AnalyzerがTCP or UDPしかサポートしていないのでTCPを選択しました。
パスの作成と分析
をクリックしてしばらく待つと可達のステータス
が到達可能
となりました。
詳細な通信経路も確認できます。Network Firewallをしっかり通っていますね。
戻りの経路(リバースパス)も認識されています。
しかし、よくよく見るとFIREWALL_UNSUPPORTED_HIGHER_PRIORITY_RULES
と共にこのパスのトラフィックに一致する可能性がある優先度がより高いルールが少なくとも 1 つありますが、これにはサポートされていないルールタイプが含まれているため、無視されました。「documentation」を参照してください。
とメッセージが出力されています。
確かにnetwork-firewall-policy-default
という設定していないファイアウォールポリシーで評価されているようです。
FIREWALL_UNSUPPORTED_HIGHER_PRIORITY_RULES
にカーソルを合わせると以下のようなJSONのポップアップが表示されました。
{
"additionalDetailType": "FIREWALL_UNSUPPORTED_HIGHER_PRIORITY_RULES",
"ruleOptions": [],
"ruleGroupTypePairs": [],
"ruleGroupRuleOptionsPairs": [
{
"ruleGroupArn": "arn:aws:network-firewall:us-east-1:<AWSアカウントID>:stateful-rulegroup/network-firewall-rule-group-5-tuple",
"ruleOptions": [
{
"keyword": "msg",
"settings": [
"\"TLS/443 pass\""
]
},
{
"keyword": "rev",
"settings": [
"1"
]
}
]
},
{
"ruleGroupArn": "arn:aws:network-firewall:us-east-1:<AWSアカウントID>:stateful-rulegroup/network-firewall-rule-group-5-tuple",
"ruleOptions": [
{
"keyword": "msg",
"settings": [
"\"HTTP/80 reject\""
]
},
{
"keyword": "rev",
"settings": [
"1"
]
}
]
}
],
"loadBalancers": []
}
これはルールにmsg
やrev
など無効なルールオプションを指定すると、ルールが評価されないということでしょうか。
試しにルールオプションからmsg
やrev
を削除します。
$ aws network-firewall describe-rule-group \
--rule-group-name network-firewall-rule-group-5-tuple \
--type STATEFUL \
--query "RuleGroup.RulesSource"
{
"StatefulRules": [
{
"Action": "PASS",
"Header": {
"Protocol": "TLS",
"Source": "$HOME_NET",
"SourcePort": "ANY",
"Direction": "FORWARD",
"Destination": "$EXTERNAL_NET",
"DestinationPort": "443"
},
"RuleOptions": [
{
"Keyword": "sid",
"Settings": [
"1000001"
]
}
]
},
{
"Action": "REJECT",
"Header": {
"Protocol": "HTTP",
"Source": "$HOME_NET",
"SourcePort": "ANY",
"Direction": "FORWARD",
"Destination": "$EXTERNAL_NET",
"DestinationPort": "80"
},
"RuleOptions": [
{
"Keyword": "sid",
"Settings": [
"1000002"
]
}
]
}
]
}
この状態で再度パスの分析を行います。
結果を確認するとFIREWALL_UNSUPPORTED_HIGHER_PRIORITY_RULES
などのメッセージは出力されなくなりましたが、変わらずnetwork-firewall-policy-default
という設定していないファイアウォールポリシーで評価されているようです。
ギブアップです。
TCP/80の通信経路チェック
TCP/443は一旦置いておいて、TCP/80の通信経路チェックを行います。
送信先ポートに80を指定して、TCP/80のパスの作成と分析を行います。
分析結果を確認すると、HTTP/80でrejectしているはずが、到達可能となっています。
また、こちらもnetwork-firewall-policy-default
という設定していないファイアウォールポリシーで評価されているようです。
ここで閃きました。
ルールグループで定義しているルールでTCP/UDPよりも上位のレイヤーのプロトコルを使っている場合は、評価されないのでは と。
試しにTLSやHTTPをTCPに変更して再チャレンジします。
$ aws network-firewall describe-rule-group \
--rule-group-name network-firewall-rule-group-5-tuple \
--type STATEFUL \
--query "RuleGroup.RulesSource"
{
"StatefulRules": [
{
"Action": "PASS",
"Header": {
"Protocol": "TCP",
"Source": "$HOME_NET",
"SourcePort": "ANY",
"Direction": "FORWARD",
"Destination": "$EXTERNAL_NET",
"DestinationPort": "443"
},
"RuleOptions": [
{
"Keyword": "sid",
"Settings": [
"1000001"
]
}
]
},
{
"Action": "REJECT",
"Header": {
"Protocol": "TCP",
"Source": "$HOME_NET",
"SourcePort": "ANY",
"Direction": "FORWARD",
"Destination": "$EXTERNAL_NET",
"DestinationPort": "80"
},
"RuleOptions": [
{
"Keyword": "sid",
"Settings": [
"1000002"
]
}
]
}
]
}
この状態で再度分析をすると、到達不可能
となりました。
rejectのルールグループやルールも表示されていますね。
詳細を展開すると、以下のようにより詳細なルールを確認することができます。$HOME_NET
と$EXTERNAL_NET
は展開されていますね。$EXTERNAL_NET
は$HOME_NET
で定義したネットワークアドレス以外となっていることも分かります。
{
"addresses": [],
"availabilityZones": [],
"cidrs": [],
"component": {
"id": "network-firewall",
"arn": "arn:aws:network-firewall:us-east-1:<AWSアカウントID>:firewall/network-firewall"
},
"explanationCode": "FIREWALL_RULES_RESTRICTION",
"loadBalancerTargetGroups": [],
"portRanges": [],
"protocols": [],
"securityGroups": [],
"vpc": {
"id": "vpc-01167e67d44f46d18",
"arn": "arn:aws:ec2:us-east-1:<AWSアカウントID>:vpc/vpc-01167e67d44f46d18"
},
"firewallStatefulRule": {
"ruleGroupArn": "arn:aws:network-firewall:us-east-1:<AWSアカウントID>:stateful-rulegroup/network-firewall-rule-group-5-tuple",
"sources": [
"10.1.1.0/24"
],
"destinations": [
"128.0.0.0/1",
"64.0.0.0/2",
"32.0.0.0/3",
"16.0.0.0/4",
"0.0.0.0/5",
"12.0.0.0/6",
"8.0.0.0/7",
"10.1.0.0/24",
"10.1.2.0/23",
"11.0.0.0/8",
"10.1.4.0/22",
"10.128.0.0/9",
"10.1.8.0/21",
"10.64.0.0/10",
"10.32.0.0/11",
"10.0.0.0/16",
"10.1.32.0/19",
"10.2.0.0/15",
"10.4.0.0/14",
"10.1.16.0/20",
"10.1.64.0/18",
"10.8.0.0/13",
"10.16.0.0/12",
"10.1.128.0/17"
],
"sourcePorts": [
{
"from": 0,
"to": 65535
}
],
"destinationPorts": [
{
"from": 80,
"to": 80
}
],
"protocol": "TCP",
"ruleAction": "reject",
"direction": "FORWARD"
}
}
TCP/443の通信経路チェック (2回目)
ということは、TCP/443の通信経路チェックも自分が設定したルールグループで評価されるのようになったのではないでしょうか。
再度実行すると、確かに自分が設定したルールグループのルールでpassされたことが分かります。
Network FirewallでTCP/UDPよりも上位のレイヤーのプロトコルを使っているルールを使用している場合は注意が必要ですね。
試しにrev
というルールオプションを追加して再度実行してみます。
$ aws network-firewall describe-rule-group \
--rule-group-name network-firewall-rule-group-5-tuple \
--type STATEFUL \
--query "RuleGroup.RulesSource"
{
"StatefulRules": [
{
"Action": "PASS",
"Header": {
"Protocol": "TCP",
"Source": "$HOME_NET",
"SourcePort": "ANY",
"Direction": "FORWARD",
"Destination": "$EXTERNAL_NET",
"DestinationPort": "443"
},
"RuleOptions": [
{
"Keyword": "sid",
"Settings": [
"1000001"
]
},
{
"Keyword": "rev",
"Settings": [
"1"
]
}
]
},
{
"Action": "REJECT",
"Header": {
"Protocol": "TCP",
"Source": "$HOME_NET",
"SourcePort": "ANY",
"Direction": "FORWARD",
"Destination": "$EXTERNAL_NET",
"DestinationPort": "80"
},
"RuleOptions": [
{
"Keyword": "msg",
"Settings": [
"\"HTTP/80 reject\""
]
},
{
"Keyword": "sid",
"Settings": [
"1000002"
]
},
{
"Keyword": "rev",
"Settings": [
"1"
]
}
]
}
]
}
実行すると意図したルールグループで評価されていますが、FIREWALL_UNSUPPORTED_RULE_OPTIONS
でサポートされていないルールオプションがあると表記されました。
詳細を確認すると、確かに追加したrev
がリストアップされていますね。
{
"additionalDetailType": "FIREWALL_UNSUPPORTED_RULE_OPTIONS",
"ruleOptions": [
{
"keyword": "rev",
"settings": [
"1"
]
}
],
"ruleGroupTypePairs": [],
"ruleGroupRuleOptionsPairs": [],
"loadBalancers": []
}
TCP/587の通信経路チェック
次にTCP/587の通信経路チェックを行います。
現在ファイアウォールポリシーでデフォルトアクションは何も指定していません。そのため、TCP/587などルールにマッチしない通信は通るはずです。
送信先ポートに587を指定して、TCP/587のパスの作成と分析を行います。
分析結果を確認すると、確かに到達可能
となっていますね。
どうやらnetwork-firewall-policy-default
というファイアウォールポリシーはルールグループに設定したルールにマッチしない場合に表示されるようですね。
TCPのポートを指定しない場合の通信経路チェック
ついでにTCPのポートを指定しない場合の通信経路チェックを行います。
送信先ポートに何も指定せず、パスの作成と分析を行います。
結果を確認すると到達可能となっています。気になるポートを確認すると0-79
となっていますね。TCP/0からTCP/79にマッチするルールはないためnetwork-firewall-policy-default
で評価されています。
TCP/587の通信経路チェック (暗黙的な拒否)
暗黙的な拒否を設定している場合、正しく判定されるのか気になってきました。
ファイアウォールポリシーのステートフルデフォルトアクションにaws:drop_established
を設定します。
$ aws network-firewall describe-firewall-policy \
--firewall-policy-name network-firewall-policy \
--query "FirewallPolicy.{StatefulRuleGroupReferences : StatefulRuleGroupReferences, StatefulDefaultActions : StatefulDefaultActions}"
{
"StatefulRuleGroupReferences": [
{
"ResourceArn": "arn:aws:network-firewall:us-east-1:<AWSアカウントID>:stateful-rulegroup/network-firewall-rule-group-5-tuple",
"Priority": 1
}
],
"StatefulDefaultActions": [
"aws:drop_established"
]
}
これにより、TCPのコネクションを確立後ルールにマッチしない通信はドロップされます。
tracerouteは到達可能です。
$ sudo traceroute -T -p 587 email-smtp.us-east-1.amazonaws.com
traceroute to email-smtp.us-east-1.amazonaws.com (34.205.148.75), 30 hops max, 60 byte packets
1 * * *
2 * * *
3 ip-10-1-1-4.ec2.internal (10.1.1.4) 1.950 ms 3.531 ms 3.512 ms
4 * * *
5 ec2-34-205-148-75.compute-1.amazonaws.com (34.205.148.75) 3.936 ms 3.608 ms 3.870 ms
Network Firewallにおける暗黙的な拒否の詳細は以下記事を参照ください。
TCP/587の分析パスを実行をすると、到達不可能となりました。network-firewall-policy-default
(確立された接続のパケットをドロップ)でdropともなっていますね。
詳細を確認すると以下のようになっていました。
{
"addresses": [],
"availabilityZones": [],
"cidrs": [],
"component": {
"id": "network-firewall",
"arn": "arn:aws:network-firewall:us-east-1:<AWSアカウントID>:firewall/network-firewall"
},
"explanationCode": "FIREWALL_RULES_RESTRICTION",
"loadBalancerTargetGroups": [],
"portRanges": [],
"protocols": [],
"securityGroups": [],
"vpc": {
"id": "vpc-01167e67d44f46d18",
"arn": "arn:aws:ec2:us-east-1:<AWSアカウントID>:vpc/vpc-01167e67d44f46d18"
},
"firewallStatefulRule": {
"ruleGroupArn": "arn:aws:network-firewall:us-east-1:<AWSアカウントID>:firewall-policy/network-firewall-policy-default",
"sources": [],
"destinations": [],
"sourcePorts": [],
"destinationPorts": [],
"ruleAction": "drop"
}
}
TCP/443の通信経路チェック (暗黙的な拒否)
暗黙的な拒否が動作することが分かりました。
次にTCP/443で許可しているルールをTLS/443に変更した場合、暗黙的な拒否でドロップされるか確認します。
以前の検証で「確立された接続のパケットをドロップ」としている場合、HTTPなどTCPよりも上位のレイヤーで許可しているルールがあれば通信できることを確認しました。
同じような挙動をReachability Analyzerがしてくれるのか確認します。
まず、TCP/443で許可しているルールをTLS/443に変更します。
$ aws network-firewall describe-rule-group \
--rule-group-name network-firewall-rule-group-5-tuple \
--type STATEFUL \
--query "RuleGroup.RulesSource"
{
"StatefulRules": [
{
"Action": "PASS",
"Header": {
"Protocol": "TLS",
"Source": "$HOME_NET",
"SourcePort": "ANY",
"Direction": "FORWARD",
"Destination": "$EXTERNAL_NET",
"DestinationPort": "443"
},
"RuleOptions": [
{
"Keyword": "sid",
"Settings": [
"1000001"
]
},
{
"Keyword": "rev",
"Settings": [
"1"
]
}
]
},
{
"Action": "REJECT",
"Header": {
"Protocol": "TCP",
"Source": "$HOME_NET",
"SourcePort": "ANY",
"Direction": "FORWARD",
"Destination": "$EXTERNAL_NET",
"DestinationPort": "80"
},
"RuleOptions": [
{
"Keyword": "msg",
"Settings": [
"\"HTTP/80 reject\""
]
},
{
"Keyword": "sid",
"Settings": [
"1000002"
]
},
{
"Keyword": "rev",
"Settings": [
"1"
]
}
]
}
]
}
その後、TCP/443のパスの分析を実行します。
結果を確認すると到達不可能となっていました。
やはりTCPよりも上位のレイヤーのプロトコルでルールを定義している場合は、気をつけた方が良さそうです。
Public SubnetからNetwork Firewallへのルートを削除した状態の通信経路チェック
最後にPublic SubnetからNetwork Firewallへのルートを削除した状態の通信経路チェックを行います。
ついつい戻りの通信用のルートの定義を忘れがちなので、それの検知ができるか気になりました。
Public SubnetのルートテーブルからNetwork Firewallへのルートを削除します。
ルート削除は以下のようになります。
また、TLS/443で許可していたルールはTCP/443で許可するように変更します。
この状態でパスを分析すると、到達可能になってしまいました。
しかし、よくよく見るとUNIDIRECTIONAL_PATH_ANALYSIS_ONLY
と表示されており、戻りの通信で何かしら不具合があったことが分かります。
可達のステータスのみで判断するではなく、パス内で表示されるメッセージも確認する必要がありますね。
待望のAWS Network Firewallに対応しました
Amazon VPC Reachability AnalyzerがAWS Network Firewallを含む3つのネットワークサービスをサポートしたアップデートを紹介しました。
個人的には待望のAWS Network Firewallの対応です。まさかルールの評価まで確認してくれるとは思いませんでした。少しクセはありますが、使いこなせば通信経路チェックに非常に役立ちそうです。
この記事が誰かの助けになれば幸いです。
以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!