なぜネットワークACLでなくセキュリティグループで細かいトラフィック制御を行なうのか
ネットワークACLとセキュリティグループの違い
まず表題の理由を述べる前に、ネットワークACLとセキュリティグループの違いを抑えておきましょう。
設定対象
- ネットワークACLはサブネット単位で設定します。サブネット以下の全インスタンスが影響を受けます。各サブネットは必ずいずれか一つのネットワークACLと紐付ける必要があります。設定しない場合デフォルトのネットワークACLが勝手に紐付きます。
- セキュリティグループはインスタンス単位で設定します。各インスタンスには少なくとも 1 つのセキュリティグループを紐付ける必要があります。言い換えれば複数個のセキュリティグループを紐付けることも可能です。
下の図はVPC外とVPC内インスタンス間の通信経路について示した図です。ネットワークACLがサブネットに紐付いていること、セキュリティグループがインスタンスに紐付いていることを把握いただければと思います。
設定内容
- ネットワークACLは許可ルール、拒否ルール両方設定します。ルール毎にルール番号を設定し、番号の低い順から評価されます。
- セキュリティグループはデフォルト通信拒否です。許可ルールのみを設定していきます。
ステートレス vs ステートフル
- ネットワークACLはステートレスです。どういうことかというと、戻りの通信(インバウンドトラフィックに対する応答のアウトバウンドトラフィック、アウトバウンドトラフィックに対する応答のインバウンドトラフィック)は、行きの通信とは別に評価されます。つまり設定次第ではインバウンド通信は受け付けるけど、その戻りのアウトバウンド通信が出ていけない、みたいな設定をすることができますし、誤ってそういう設定にしてしまう可能性があります。
- 対してセキュリティグループはステートフルです。ネットワークACLとは異なり、戻りの通信(インバウンドトラフィックに対する応答のアウトバウンドトラフィック、アウトバウンドトラフィックに対する応答のインバウンドトラフィック)は、行きの通信が許可されている限り自動的に許可されます。
さて、では本題の「ネットワークACLでは全トラフィックを許可して、セキュリティグループで細かい設定をする」理由を説明します。
ネットワークACLでは同一サブネット内の通信制御設定ができない
前述のとおりネットワークACLはサブネットに紐づくリソースです。サブネットのインバウンドとアウトバウンドのトラフィックに関して制御することができます。言い換えると同一サブネット内のインスタンス間の通信はネットワークACLを通らないので制御できません。このような場合にはセキュリティグループを利用する必要があります。
セキュリティグループは送信元/先ルールをセキュリティグループIDで設定できるのが便利
ネットワークACLのルールに設定するのは、ポートとCIDRです。インバウンドルールであれば、ポート〇〇のCIDR xx.xx.xx.xx/24 からのインバウンドトラフィックを許可(拒否)するとか、アウトバウンドルールであればポート▲▲のCIDR yy.yy.yy.yy/32 へのアウトバウンドトラフィックを許可(拒否)するとかいったルールを書いていきます。
セキュリティグループも同様にポートとCIDRを指定してルールを書いていきます。が、CIDRの代わりにセキュリティグループIDを指定することもできます。インバウンドルールであれば、セキュリティグループhogeがアタッチされているリソースからへのポート〇〇のインバウンドトラフィックを許可する、といった設定ができます。アウトバウンドルールも同様で、セキュリティグループfugaがアタッチされているリソースからへのポート▲▲へのアウトバウンドを許可するといった設定ができます。
これを使用することで、CIDRでは設定できないよりきめ細やかな、もしくはより柔軟なアクセス制御ができます。例として、ALBとその配下のEC2間の通信を考えてみましょう。
ALBはAZ-AとAZ-Cのパブリックサブネットにまたがって配置されるとします。
EC2としては、インバウンドトラフィックはALBからの80番ポートへのアクセスのみを許可したいです。これをCIDRで設定する場合、ALBのIPは固定されないので、ALBのIPになりえるCIDRすべて、つまりAZ-AとAZ-CのパブリックサブネットのCIDRを許可する必要があります。こうした場合、これらのサブネット内のALB以外のリソースからもアクセスを許可していることになります。
セキュリティグループのIDを使う場合は、ALBにアタッチするセキュリティグループのIDを控えておき、このIDのセキュリティグループをアタッチしているリソースからの80番ポートアクセスを許可する、という設定が可能です。こうすることで、ALBのIPが変化しても変わらず80番アクセスは可能ですし、サブネット内のALB以外のリソースからのアクセスはブロックすることができます。
ネットワークACLはEphemeralポートのことを考慮する必要がある
ステートレス vs ステートフルの欄で説明しましたが、ネットワークACLは戻りのトラフィックについても制御する必要があります。戻りのトラフィックにはよくEphemeralポートが使われます。Ephemeralポートは一時ポートのことです。このポート、クライアントのOSによってポート番号レンジが変わります。
リクエストを開始するクライアントは、一時ポートの範囲を選択します。範囲は、クライアントのオペレーティングシステムによって変わります。
- 多くの Linux カーネル (Amazon Linux カーネルを含む) は、ポート 32768~61000 を使用します。
- Elastic Load Balancing が送信元のリクエストは、ポート 1024~65535 を使用します。
- Windows Server 2003 を介する Windows オペレーティングシステムは、ポート 1025~5000 を使用します。
- Windows Server 2008 以降のバージョンでは、ポート 49152~65535 を使用します。
- NAT ゲートウェイはポート 1024~65535 を使用します。
- AWS Lambda 関数は、ポート 1024-65535 を使用します。
たとえば、インターネット上の Windows XP クライアントから、お使いの VPC のウェブサーバーにリクエストが送信される場合、ネットワーク ACL には、ポート 1025 ~ 5000 あてのトラフィックを可能にするアウトバウンドルールを用意する必要があります。
VPC 内のインスタンスが、リクエストを開始するクライアントの場合、ネットワーク ACL には、インスタンス (Amazon Linux、Windows Server 2008 など) の種類に固有の一時ポートあてのトラフィックを可能にするインバウンドルールを用意する必要があります。
実際に、VPC 内のパブリックに面したインスタンスに対して、トラフィックを開始することができる多様なクライアントを対象にするには、一時ポート 1024~65535 を開くことができます。ただし、その範囲内で悪意のあるポートのトラフィックを拒否するルールを ACL を追加することもできます。このとき、テーブル内で、幅広い範囲の一時ポートを開く許可ルールよりも先に拒否ルールを配置します。
この設定が気づきにくいです。例えば最初はLinuxOS間のみのトラフィックしか想定していなかったのでポート 32768~61000を許可していたが、その後Windows ServerもVPC内に設置することになったとします。Ephemeralポートの値が異なるので許可ポートレンジを変更する必要がありますが、そのことに気づけずハマる、という可能性があります。ですので本当に必要な場合を除きあまりネットワークACLで細かな設定をしたくありません。
両方で細かく設定すると変更が面倒
ネットワークACL、セキュリティグループ両方で許可されたトラフィックのみが通信許可されます。もし途中で通信要件が変わった場合、ネットワークACL、セキュリティグループ両方で細かいを設定をしていると両方の設定を変更しない限り疎通できません。それが面倒なので、より細かな設定ができるセキュリティグループでのみ細かい設定をしてネットワークACLは全許可などゆるい設定にしていることが多いです。
まとめ
ネットワークACLとセキュリティグループの使い分けについて意見をまとめました。もちろん「基本こうしている」というだけなので、厳しいトラフィック制御が求められているときはネットワークACLでも制御をすることがあります。また所謂ブロックリストなど広範囲にまたがる設定であればサブネット単位で適用されるネットワークACLで設定するほうが便利な場合もあります。違いを理解していること、また使い分けの方針を関係者間で共有できていることが大事なのではと思います。