こんにちは、マネージドサービス部の大城です。
小ネタです。EC2のアウトバウンド通信を拒否する方法を考えてみました。
なぜアウトバウンドを拒否するのか
最近は便利な世の中でAPIキーさえあれば外部との連携が容易です。アプリケーション内で外部APIを実行するだけで便利なことができたり、EC2にインストールされているAgentから外部にデータをストリーミングできたりします。
このような設定が施されたEC2のAMIを取得し、別の環境にデプロイした場合、本番環境で連携している外部APIをデプロイした環境から誤って実行する可能性があります。
アウトバウンドを拒否しなくても EC2 で使う外部APIキーを AWS Secrets Manager や AWS Systems Manager Parameter Store などで外部保管することで事故を防ぐことができます。また、内部に持っていたとしてもデプロイするタイミングでダミー化することで事故を防ぐことができます。
しかし、歴史があるアプリケーションで中身がブラックボックス化していたり、デプロイするのが「なんとなく怖い」AMIもあるかもしれません。そのような場合、インフラ側でアウトバウンドを拒否したほうが安全です。
考えられる方法
AMI デプロイ時に特定ポートのアウトバウンドを拒否する方法として3つが思いつきます。
- NACLで拒否する
- セキュリティグループで拒否する
- OS機能のFireWallで拒否する
NACLで拒否する
AWSのドキュメントにも記載されている方法で、EC2が所属するサブネットにNACLでアウトバウンドを拒否することができます。
シンプルで一番簡単な方法です。下のようにNACLのアウトバウンドルールにHTTPS(443)拒否を追加設定すればOKです。
アウトバウンドルール
ルール番号 | タイプ | プロトコル | ポート範囲 | 送信元 | 許可/拒否 |
---|---|---|---|---|---|
100 | HTTPS(443) | TCP(6) | 443 | 0.0.0.0/0 | Deny |
110 | すべてのトラフィック | すべて | すべて | 0.0.0.0/0 | Allow |
* | すべてのトラフィック | すべて | すべて | 0.0.0.0/0 | Deny |
セキュリティグループで拒否する
NACLで拒否するのが一番簡単ですが、サブネット単位ではなく EC2 単体で拒否する方法としてセキュリティグループを使うこともできます。
セキュリティグループは許可ルールを設定して使うのが普通ですが、書き方を工夫すれば結果的に特定ポートのアウトバウンドを拒否する設定ができます。
セキュリティグループの仕様を今一度確認してみます
セキュリティグループを最初に作成するとき、リソースからのすべてのアウトバウンドトラフィックを許可するアウトバウンドルールが設定されます。ルールを削除し、任意の発信トラフィックのみを許可するアウトバウンドルールを追加できます。セキュリティグループにアウトバウンドルールがない場合、アウトバウンドトラフィックは許可されません。
拒否ルールは記載することが出来ませんが、アウトバウンドルールを削除し、許可ルールを細かく記載することで、結果的に特定ポートのアウトバウンドを拒否する設定となります。
具体的には下のような設定となります。面倒な設定ですが出来ないことはないです。
https(443) TCP のアウトバウンドを拒否したい場合
セキュリティグループのアウトバウンドを下のとおり、https(443) TCP以外を許可する設定にします。VPCのCIDR、IPv6についてはすべて許可しています。
Name | IP バージョン | タイプ | プロトコル | ポート範囲 | 送信先 |
---|---|---|---|---|---|
1 | IPv4 | カスタム TCP | TCP | 0 - 442 | 0.0.0.0/0 |
2 | IPv4 | カスタム TCP | TCP | 444 - 65535 | 0.0.0.0/0 |
3 | IPv4 | すべてのトラフィック | すべて | すべて | 172.31.0.0/16 ※VPCのCIDR |
4 | IPv4 | すべての UDP | UDP | 0 - 65535 | 0.0.0.0/0 |
5 | IPv4 | すべての ICMP - IPv4 | ICMP | すべて | 0.0.0.0/0 |
6 | IPv6 | すべてのトラフィック | すべて | すべて | ::/0 |
SMTP関連(25,465,587) TCP のアウトバウンドを拒否したい場合
こちらも同様にSMTP関連(25,465,587) TCP以外を許可する設定にします。VPCのCIDR、IPv6についてはすべて許可しています。
Name | IP バージョン | タイプ | プロトコル | ポート範囲 | 送信先 |
---|---|---|---|---|---|
1 | IPv4 | カスタム TCP | TCP | 0 - 24 | 0.0.0.0/0 |
2 | IPv4 | カスタム TCP | TCP | 26 - 464 | 0.0.0.0/0 |
3 | IPv4 | カスタム TCP | TCP | 466 - 586 | 0.0.0.0/0 |
4 | IPv4 | カスタム TCP | TCP | 588 - 65535 | 0.0.0.0/0 |
5 | IPv4 | すべてのトラフィック | すべて | すべて | 172.31.0.0/16 ※VPCのCIDR |
6 | IPv4 | すべての UDP | UDP | 0 - 65535 | 0.0.0.0/0 |
7 | IPv4 | すべての ICMP - IPv4 | ICMP | すべて | 0.0.0.0/0 |
8 | IPv6 | すべてのトラフィック | すべて | すべて | ::/0 |
注意点
複数のセキュリティグループをEC2にアタッチすると、or条件で許可ルールが有効になります。
片方のセキュリティグループですべてのアウトバウンドトラフィックを許可するアウトバウンドルールが設定されている場合、結果的に通信出来てしまうのでアタッチするセキュリティグループは一つにしたほうが良いです。
OS機能のFireWallで拒否する
EC2デプロイ時のユーザーデータにスクリプトを記載する方法が考えられます。ただし、個人的にこの方法は微妙だと思っています。スクリプトが失敗した場合にアウトバウンド拒否ができないのと、スクリプトを実行する前に外部APIを実行される可能性も考えられるためです。
Amazon Linux 2023の場合だと下のスクリプトをユーザーデータに設定することでhttps(443) TCP のアウトバウンドを拒否することができました。
#!/bin/bash yum install -y firewalld systemctl start firewalld firewall-cmd --permanent --direct --add-rule ipv4 filter OUTPUT 1 -m state --state NEW -m tcp -p tcp -d 0.0.0.0/0 --dport 443 -j DROP firewall-cmd --reload systemctl enable firewalld
WindowsだとWindowsファイアーウォールを設定するスクリプトを書いたら同じことができると思いますが試していません。(すみません)
最後に
ここまで読んでいただきありがとうございます。この記事が誰かの役に立ったら幸いです。
大城 慶明 (記事一覧)
マネージドサービス部
2022年10月サーバーワークスに入社、沖縄からリモート勤務。AWSを勉強中。沖縄では大城が多いので「よっさん」と呼ばれています。AWS14冠。NRUG沖縄支部運営。X @yo_ohshiro