ECSからの不審な外向き通信を見つけて遮断する ── VPCフローログとネットワークACL

目次

概要

コンテナが侵害されたとき、最初に現れる兆候は「見慣れない宛先への外向き通信」です。マイニングプールへの接続、外部への大量のデータ送信、見慣れないポートへの定期的なアクセス。攻撃者がコンテナの中で何をしているかは見えなくても、通信が起きた事実はネットワーク側に残ります。

この事実を記録するのがVPCフローログです。そして、見つけた通信をサブネット単位で止めるのがネットワークACL(NACL)です。CloudTrailはAPIコールの記録なので、コンテナからインターネットへの通信は写りません。AWS WAFやShieldは受信側の防御であって、外向きの通信には効きません。

この記事では、ECSタスクから外部への通信をフローログで観測し、CloudWatch Logs Insightsで宛先ポートごとに集計して不審な通信を特定し、NACLで遮断してREJECTに変わることを確認します。

外向き通信の検知と遮断 ── 観測はフローログ、遮断はネットワークACL
外向き通信の検知と遮断 ── 観測はフローログ、遮断はネットワークACL
クラウドおさる

ECSタスクの外向き通信をフローログで捕まえ、宛先ポートごとに集計し、NACLで止めて REJECT に変わるところまで確かめるでござる。検出はフローログ、遮断はNACL、この対応を手で覚えるのでござるな。

この記事のメリット

  • 外向き通信の調査に、なぜCloudTrailやWAFではなくフローログを使うのかを説明できるようになる
  • フローログのレコード形式と action フィールドの読み方が分かるようになる
  • CloudWatch Logs Insightsで宛先ポート別に集計するクエリが書けるようになる
  • セキュリティグループとネットワークACLの使い分け(ステートフル / ステートレス)を判断できるようになる
  • SCS試験でネットワークレベルの検知と遮断を問う設問に答えられるようになる

執筆者とキャラクター紹介

執筆者:土肥(とひ)

株式会社ジェニュインの代表であり元エンジニア。これまでオンプレミスと AWS 環境のインフラ業務を担当。AWS 認定資格の学習で得た知識を、ハンズオンとともに解説するのが得意。直近では新人の教育も行っており、これから技術を学ぶ方が納得できる解説を心がけています。基礎編・Cloud Practitioner の記事では、解説役としても登場します。

土肥

クラウドおさる

クラウドおさる

はじめましてでござる。弊猿はクラウドおさる。IT インフラが異常に発達した猿山から、雲に乗って地上の AWS を学びに降りてきたのでござる。

クラウドおさる

基礎編や Cloud Practitioner の記事では、とひさんに素朴な疑問をぶつける役でござるな。Security - Specialty などの記事では、要所でワンポイントや注意点をひとこと添えるでござる。

クラウドおさる

猿山にもデータセンターや監視当番があって、地上で起きることはだいたい猿山にも同じ仕組みがあるのでござる。例え話がつい猿山に寄るのは、弊猿の癖でござる。

技術解説

外向き通信の調査に何を使うか

サービス記録・制御するものこの用途で使えるか
VPCフローログネットワークインターフェイスを出入りするIPトラフィックのメタデータ使える。送信元・宛先・ポート・許可/拒否が分かる
CloudTrailAWS APIの呼び出し使えない。コンテナから外部への通信はAPIコールではない
AWS WAFALB・CloudFrontなどへの受信リクエスト使えない。外向きの通信は対象外
AWS ShieldDDoS攻撃からの保護(受信)使えない
GuardDuty脅威検出(フローログ・DNSログ・CloudTrailを分析)検知には使える。ただし遮断はしない

設問では「不正な外向き通信を検出して遮断する」という形で問われます。検出はフローログ、遮断はNACLかセキュリティグループ、という対応で覚えます。

フローログのレコードを読む

既定の記録形式は14個のフィールドで構成されます。

フィールド内容
version / account-id / interface-idバージョン・アカウントID・ENI ID
srcaddr / dstaddr送信元・宛先のIPアドレス
srcport / dstport送信元・宛先のポート
protocolIANAのプロトコル番号(6=TCP、17=UDP)
packets / bytesパケット数・バイト数
start / endフローの開始・終了時刻(UNIX秒)
actionACCEPT または REJECT
log-statusログの記録状態

CloudWatch Logs Insightsでは、これらのフィールドが srcAddr / dstAddr / dstPort / action / bytes のような名前で自動的に検出されます。クエリでは、レコード形式の srcaddr ではなく srcAddr のように大文字を含む名前で書く点に注意が必要です。

action の意味は次のとおりです。

値意味
ACCEPTトラフィックが許可された
REJECTセキュリティグループやネットワークACLで許可されなかった、接続終了後にパケットが届いた、など

遮断が効いたかどうかは、この action が ACCEPT から REJECT に変わることで確認できます。

集約間隔は既定で最大10分、オプションで最大1分を指定できます(Nitroベースのインスタンスでは、指定に関わらず1分以下に短縮されます)。集約後、CloudWatch Logsへはおよそ5分、S3へはおよそ10分で配信されます。フローログはリアルタイムではない、という点は運用でも試験でも押さえておきます。

フローログのレコード ── 遮断が効くと action が ACCEPT から REJECT に変わる
フローログのレコード ── 遮断が効くと action が ACCEPT から REJECT に変わる
クラウドおさる

遮断が効いたかどうかは、action が ACCEPT から REJECT に変わることで分かるでござる。ただし猿山の門番の帳面と同じで、集約してから数分遅れで届くので、フローログはリアルタイムではないのでござるな。

セキュリティグループとネットワークACL

見つけた通信を止める手段は2つあります。性質が違うので使い分けます。

観点セキュリティグループネットワークACL
適用先ENI(インスタンス・タスク単位)サブネット
状態ステートフル(戻りの通信は自動的に許可)ステートレス(戻りの通信も明示的に許可が要る)
ルール許可のみ許可と拒否の両方
評価すべてのルールを評価するルール番号の小さい順に評価し、最初に一致したもので決まる

「特定の宛先ポートへの通信を拒否したい」という要件では、拒否ルールが書けるNACLを使います。セキュリティグループには拒否ルールがなく、「許可を外す」ことしかできないためです。

NACLはステートレスなので、アウトバウンドを拒否するときは戻りの通信にも注意が必要です。ただし今回のように「特定の宛先ポートへの発信を止める」用途では、アウトバウンドの拒否ルールを1本入れれば足ります。

セキュリティグループとネットワークACL ── 拒否ルールを書けるのはNACLだけ
セキュリティグループとネットワークACL ── 拒否ルールを書けるのはNACLだけ
クラウドおさる

セキュリティグループには拒否ルールが無く、許可を外すことしかできぬでござる。特定の宛先ポートを拒否したいならNACL、そしてNACLはステートレスで戻りの通信にも効く点に気をつけるでござるぞ。

調査の流れ

  1. フローログをCloudWatch Logsに出す(対象はVPC・サブネット・ENIのいずれか)
  2. CloudWatch Logs Insightsで、宛先ポートや宛先IPごとに集計する
  3. 想定していない宛先・ポートを特定する
  4. NACLの拒否ルールで遮断する
  5. フローログで REJECT に変わったことを確認する

恒久対策としては、そもそもタスクをプライベートサブネットに置いてNATゲートウェイ経由に限定する、必要な宛先だけVPCエンドポイントで通す、といった構成に寄せます。NACLでの遮断は「いま出ている通信を止める」応急処置です。

フリーランス案件
クラウドおさる
クラウドキャリアフリーランス

AWS の実務経験があるなら、単価を上げにいく

AWS に特化したフリーランスエージェントです。以下は取り扱い案件の一例です。設計・SRE・セキュリティ・生成 AI の領域で、専門を掛け合わせるほど単価が上がります。

横にスクロールできます。掲載時点の情報のため、募集が終了している場合があります。条件の近い案件をご紹介しますので、お気軽にご相談ください。

実践

ハンズオンガイド7 ステップ画面 8 枚

コンソールの横に開いて、チェックしながら進めましょう。

ガイドを開く

別タブで開きます。チェックはこのブラウザに保存されます。

パブリックサブネットのECSタスクから外部へ定期的に通信させ、フローログで観測してからNACLで遮断します。

前提条件

  • リージョン: ap-northeast-1(東京)
  • ECS・VPC・CloudWatch Logsの操作権限を持つIAMユーザーまたはロールでコンソールにログイン済みであること
  • 以下のリソースが作成済みであること
リソース種別リソース名用途
VPCecs-egress-lab-vpc(10.40.0.0/16)検証用VPC
パブリックサブネットecs-egress-lab-public(10.40.1.0/24)ECSタスクの配置先
セキュリティグループecs-egress-lab-sgタスク用(インバウンドなし・アウトバウンド全許可)
ECSクラスターecs-egress-lab-clusterFargateタスクの実行環境
タスク定義ecs-egress-lab-task外部の 1.1.1.1 の TCP 8888 番へ、5秒ごとに接続を試みるコンテナ
CloudWatchロググループ/aws/vpc/ecs-egress-labフローログの出力先
IAMロールecs-egress-lab-flowlog-roleフローログがロググループに書き込むためのロール

フローログとFargateタスクは課金対象です。

このハンズオンで作成するリソースは以下のとおりです。

リソース種別リソース名用途
VPCフローログecs-egress-lab-flowlogVPC全体のトラフィックを記録
ネットワークACLのルールアウトバウンド 90番特定ポートへの通信を拒否

手順1: VPCフローログを作成する

AWSマネジメントコンソールにログインし、リージョンが ap-northeast-1(東京)であることを確認します。

上部の検索バーに VPC と入力し、「VPC」を選択します。左側ナビゲーションの「お使いのVPC」から ecs-egress-lab-vpc を選択します。

下部の「フローログ」タブを開き、「フローログの作成」をクリックして以下を設定します。

  • 名前: ecs-egress-lab-flowlog
  • 最大集計間隔: 1 分(既定は 10 分)
  • 送信先ロググループ: /aws/vpc/ecs-egress-lab
  • サービスロール: ecs-egress-lab-flowlog-role

フィルター(すべて)、送信先(CloudWatch Logs に送信)、サービスアクセス(既存のサービスロールを使用)、ログレコードの形式(AWS のデフォルト形式)は既定のままにします。

フローログ作成画面(集計間隔・送信先ロググループ・サービスロールを設定した状態)
フローログ作成画面(集計間隔・送信先ロググループ・サービスロールを設定した状態)

その他の項目はデフォルトのままにして、「フローログを作成」をクリックします。

手順2: ECSタスクを起動する

上部の検索バーに ECS と入力し、「Elastic Container Service」を選択します。

ecs-egress-lab-cluster を開き、「タスク」タブから「新しいタスクの実行」をクリックします。

「コンピューティングオプション」で 起動タイプ(起動タイプは FARGATE)を選び、「タスク定義ファミリー」で ecs-egress-lab-task を選択します(リビジョンは「最新」のまま)。

「ネットワーキング」で以下を設定します。

  • VPC: ecs-egress-lab-vpc
  • サブネット: ecs-egress-lab-public
  • セキュリティグループ: ecs-egress-lab-sg(VPC を選ぶと自動で入る default は外します)
  • パブリック IP: オンになっています(既定のまま)
ECSタスク実行画面のネットワーキング設定
ECSタスク実行画面のネットワーキング設定

「作成」をクリックします。タスク一覧で、30秒ほどでステータスが「実行中」になることを確認します。

タスクが「実行中」になった状態
タスクが「実行中」になった状態

手順3: フローログで外向き通信を確認する

タスクは起動すると、外部の 1.1.1.1 の 8888 番ポートに向けて定期的に接続を試み続けます。集計間隔とCloudWatch Logsへの配信の都合で、記録が現れるまで数分かかります。

上部の検索バーに CloudWatch と入力し、「CloudWatch」を選択します。左側ナビゲーションの「ログ」→「ロググループ」から /aws/vpc/ecs-egress-lab を開き、eni- で始まるログストリームを開きます。

フローログのレコードが、14個のフィールドをスペースで区切った形で並んでいます。インターネット側からタスクのパブリック IP に届いた通信(セキュリティグループで拒否された REJECT)も多く記録されるため、フィルターに 1.1.1.1 と入力して、タスクからの外向き通信だけに絞り込みます。

フローログのレコード(宛先IP・宛先ポート・actionが確認できる状態)
フローログのレコード(宛先IP・宛先ポート・actionが確認できる状態)

手順4: Logs Insightsで宛先ポート別に集計する

左側ナビゲーションの「ログ」→「ログのインサイト」を開きます。クエリ画面の「ロググループ」で /aws/vpc/ecs-egress-lab を選択すると、クエリ欄の1行目に SOURCE "arn:aws:logs:…:log-group:/aws/vpc/ecs-egress-lab" が自動で入ります。

2行目以降を次のクエリにして「実行」をクリックします。タスクのプライベートIPを送信元とする通信を、宛先ポートごとに集計します。

fields @timestamp, srcAddr, dstAddr, dstPort, action, bytes
| filter srcAddr like /^10\.40\./
| stats sum(bytes) as totalBytes, count(*) as flows by dstPort, action
| sort totalBytes desc
| limit 20

結果には 443 番と 8888 番が並びます。443 番はタスク起動時のコンテナイメージの取得など、ECS が動くために必要な通信です。想定していないのは 8888 番で、継続的に通信が発生していることを確認します。

Logs Insightsの集計結果(宛先ポート別のフロー数とバイト数)
Logs Insightsの集計結果(宛先ポート別のフロー数とバイト数)

宛先IPも確認しておきます。

fields @timestamp, srcAddr, dstAddr, dstPort, action
| filter srcAddr like /^10\.40\./ and action = "ACCEPT"
| stats count(*) as flows by dstAddr, dstPort
| sort flows desc
| limit 20

8888 番の宛先が 1.1.1.1 であることが分かります。

宛先IPと宛先ポートの組み合わせで集計した結果
宛先IPと宛先ポートの組み合わせで集計した結果

手順5: ネットワークACLで遮断する

VPCコンソールの左側ナビゲーションから「ネットワーク ACL」を選択し、ecs-egress-lab-public サブネットに関連付けられているNACLを選択します。

下部の「アウトバウンドルール」タブを開き、「アウトバウンドルールを編集」をクリックします。既存のルール 100 番(すべてのトラフィックを許可)が表示されています。

「新しいルールを追加」をクリックし、追加された行に以下を設定します。

  • ルール番号: 90
  • タイプ: カスタム TCP
  • ポート範囲: 8888(手順4で特定した宛先ポート)
  • 送信先: 0.0.0.0/0
  • 許可/拒否: 拒否

既存の全許可ルール(100番)より小さい番号にする点が重要です。NACLはルール番号の小さい順に評価し、最初に一致したルールで決まります。100番のままでは既存ルールと重複して追加できず、大きい番号にすると全許可ルールが先に一致して拒否されません。

ネットワークACLのアウトバウンドルール編集画面(拒否ルールを追加した状態)
ネットワークACLのアウトバウンドルール編集画面(拒否ルールを追加した状態)

「変更を保存」をクリックします。

クラウドおさる

拒否ルールは、既存の全許可ルールより小さい番号にするのが肝でござる。NACLは番号の小さい順に評価し、最初に一致したルールで決まるのでござる。

手順6: REJECTに変わったことを確認する

数分待ってから、CloudWatch Logs Insightsで次のクエリを実行します。今回は保存から3分ほどで最初の REJECT が記録されました。

fields @timestamp, srcAddr, dstAddr, dstPort, action
| filter srcAddr like /^10\.40\./
| stats count(*) as flows by dstPort, action
| sort flows desc
| limit 20

8888 番に action が REJECT の行が現れていることを確認します。遮断前の ACCEPT の記録と、遮断後の REJECT の記録が両方残るので、遮断が効いた時点がフローログで分かります。

遮断後のLogs Insightsの結果(action が REJECT になっている状態)
遮断後のLogs Insightsの結果(action が REJECT になっている状態)

NACLはステートレスなので、アウトバウンドを拒否すると戻りの通信も届かなくなります。今回は「発信そのものを止める」ことが目的なので問題ありませんが、業務通信に適用する場合は、戻りの通信(エフェメラルポート)への影響を必ず確認します。

クラウドおさる

外向き通信の検知と遮断に、CloudTrailやWAF・Shieldではなくフローログと NACL を選べるかが試験の観点でござるな。GuardDutyは検知まで、遮断はしない、という線引きも取り違えやすいでござる。

まとめ

やりたいこと使うもの
外向き通信が起きた事実を知るVPCフローログ(CloudWatch Logs / S3)
宛先・ポートごとに集計するCloudWatch Logs Insights
特定の宛先ポートへの通信を拒否するネットワークACLの拒否ルール
タスク単位で許可を絞るセキュリティグループ(拒否は書けない)
脅威として検知させるGuardDuty(検知のみ。遮断はしない)
  • CloudTrailはAPIコールの記録なので、コンテナから外部への通信は写らない
  • WAFやShieldは受信側の防御であり、外向きの通信には効かない
  • フローログの action が ACCEPT から REJECT に変わることで、遮断が効いたと確認できる
  • NACLはステートレスかつルール番号順の評価。拒否ルールを書けるのはNACLだけ
  • フローログはリアルタイムではない(集約最大10分・配信に数分)。即時遮断の仕組みではない

参照先

フリーランス案件
クラウドおさる
クラウドキャリアフリーランス

AWS の実務経験があるなら、単価を上げにいく

AWS に特化したフリーランスエージェントです。以下は取り扱い案件の一例です。設計・SRE・セキュリティ・生成 AI の領域で、専門を掛け合わせるほど単価が上がります。

横にスクロールできます。掲載時点の情報のため、募集が終了している場合があります。条件の近い案件をご紹介しますので、お気軽にご相談ください。

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

株式会社ジェニュイン(https://genuine-pt.jp)の代表取締役.

2018年〜インフラエンジニアとしてキャリアをスタートし、オンプレミスのネットワーク・サーバ環境で3年半、クラウド環境で4年半の8年間エンジニアとして従事。
2021年に佐藤氏の創業した株式会社Luxyを引き継ぎ、代表に就任。
その後アガルートグループ内の株式会社ジェニュインと合併。
合併後同社代表に就任。

目次