Timee Product Team Blog

タイミー開発者ブログ

Kubernetes の 4C モデルで整理する ECS Fargate のサプライチェーン攻撃対策

はじめに

はじめまして、プラットフォームエンジニアリング本部に所属している徳富(@yannKazu1)です。

みなさん、サプライチェーン攻撃って気にしてますか?

npm パッケージの乗っ取り(ua-parser-js 事件)、GitHub Actions の改ざん(tj-actions/changed-files 事件)、依存パッケージへのバックドア混入(xz-utils 事件)……。ここ数年、OSS を取り巻くセキュリティの前提がガラッと変わってきています。正直、「いつ・どこから仕掛けられるかわからない」状況です。

しかもサプライチェーン攻撃って、攻撃側のコストが低いわりに被害範囲が広いのが厄介なんですよね。

そんなわけで、ECS Fargate 環境におけるサプライチェーン攻撃対策を整理してみようと思ったのですが、いきなり全部を洗い出そうとしてもカオスになるだけ。何かいいフレームワークはないかな……と探していたところ、Kubernetes の 4C セキュリティモデル(Cloud → Cluster → Container → Code) の考え方がそのまま使えそうだったので、これをベースにチェックシート的に整理してみました。

「うちの環境だとどこが手薄いんだろう?」を考えるときの参考にしてもらえればと思います。

おことわり: これをやれば完璧!というものではないです。あくまで「見通しよく整理するための道具」として 4C モデルを借りているだけなので、実際にどこまでやるかは環境やリスク許容度に応じて取捨選択してください。

整理に使う 2 つの軸

軸 1:4C セキュリティモデル —「どこを守るか」

Kubernetes の公式ドキュメントで紹介されている、クラウドネイティブセキュリティを 4 つの同心円レイヤー で捉えるモデルです。

参考: クラウドネイティブセキュリティの概要 | Kubernetes

┌─────────────────────────────────────────┐
│  Cloud(クラウド基盤)                     │
│  ┌─────────────────────────────────────┐ │
│  │  Cluster(オーケストレーター)          │ │
│  │  ┌─────────────────────────────────┐ │ │
│  │  │  Container(コンテナランタイム)    │ │ │
│  │  │  ┌─────────────────────────────┐ │ │ │
│  │  │  │  Code(アプリケーション)       │ │ │ │
│  │  │  └─────────────────────────────┘ │ │ │
│  │  └─────────────────────────────────┘ │ │
│  └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘

ポイントは 各レイヤーが外側のレイヤーの上に構築されている ということ。どれだけアプリのコードを堅牢にしても、基盤レイヤーのセキュリティが低い水準では守りきれません。だからこそ、特定のレイヤーだけに頼るのではなく、すべてのレイヤーを固める 多層防御(Defense in Depth) が基本方針になります。

ECS Fargate への読み替えはこんな感じです。

4C レイヤー K8s での意味 ECS Fargate での対応 サプライチェーン攻撃での主な攻撃面
Cloud クラウド基盤 AWS アカウント・IAM・ネットワーク IAM キー漏洩、ECR への不正 push
Cluster オーケストレーター ECS クラスター・CI/CD パイプライン CI/CD アクションの改ざん、パイプライン侵入
Container コンテナランタイム Docker イメージ・Fargate タスク ベースイメージの汚染、OS パッケージへのバックドア混入、実行時の不正プロセス
Code アプリケーションコード ソースコード・依存パッケージ パッケージ乗っ取り、typosquatting、悪意ある PR

軸 2:対策の目的 —「何のために守るか」

4C モデルは「どこを守るか」を整理するフレームワークですが、それだけだと対策が偏りがちです。そこでもうひとつ、 「何のために守るか」 という軸を加えてみます。今回は、セキュリティ対策を以下の 4 つの目的に分類して整理してみました。

目的 説明 考え方
🛡 予防(Prevention) 攻撃を未然に防ぐ そもそも悪いものを入れさせない
🔍 検知(Detection) 攻撃や脆弱性を発見する 入り込んだ・紛れ込んだことに気づく
🧱 封じ込め(Containment) 侵入後の被害を最小化する やられても被害を広げさせない
🔎 調査(Investigation) 何が起きたかを追跡する 事後に原因と影響範囲を特定する

よくある落とし穴は 「予防」ばかりに意識が向いて、他が手薄になる こと。完璧な予防は不可能なので、入り込まれた後にどう気づいて・どう被害を抑えて・どう調べるか、まで含めて考えるのが多層防御の本質です。

この記事の構成

本記事では 目的(予防・検知・封じ込め・調査)を大項目 にして、それぞれの中で 4C のどのレイヤーに対する対策か を整理していきます。


🛡 予防(Prevention)— そもそも入れさせない

攻撃を未然に防ぐための対策です。「入口を塞ぐ」イメージですね。

Cloud:VPC Endpoint

概要: AWS サービスへの通信をインターネットを経由せずに VPC 内で完結させる。

防げる攻撃:

  • 侵害されたタスクからの外部 AWS アカウントへのデータ持ち出し (Endpoint Policy で自社アカウントに限定)
  • マルウェア感染後の C2 通信・情報送信 (Egress 全遮断下でも AWS サービスは利用可能)
  • 漏洩した IAM 認証情報による外部からの不正アクセス (バケットポリシーで aws:SourceVpce を指定)

設定のポイント:

  • S3 Gateway Endpoint(無料)は必須
  • ECR、SSM、Secrets Manager、CloudWatch Logs 用の Interface Endpoint を検討
  • Endpoint Policy で aws:PrincipalAccount を制限
  • リソース側ポリシーで aws:SourceVpce を指定

Cluster:CI/CD パイプラインのハードニング

概要: GitHub Actions など CI/CD で使うサードパーティアクションを、改ざんされない形で固定する。

防げる攻撃:

  • GitHub Actions の改ざん(tj-actions/changed-files 事件のように、人気アクションのリポジトリが侵害されてタグが書き換えられるケース)
  • バージョンタグの上書きによる 意図しないコードの実行

設定のポイント:

GitHub Actions は通常 uses: actions/checkout@v4 のようにタグやブランチで指定しますが、これらは 後から書き換え可能 です。tj-actions/changed-files 事件(2025 年 3 月)では、攻撃者がメンテナーの認証情報を侵害し、既存タグを悪意あるコミットに向け直すことで、汚染されたアクションを使う CI でシークレットがビルドログに書き出されるという被害が広範囲に発生しました。一方、commit SHA でピンニングしていたユーザーは影響を受けませんでした(侵害期間中に対象 SHA へ更新していなければ)。

対策として、commit SHA でピンニングする のが推奨されます。

# Before(タグ指定 - 書き換えられる可能性あり)
- uses: actions/checkout@v4

# After(commit SHA でピンニング - 改ざんされない)
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
  • Dependabot や Renovate Bot で SHA の自動更新を設定
  • permissions: で各ジョブの GITHUB_TOKEN 権限を最小化
  • OIDC を使った AWS 認証に切り替え、長期クレデンシャルを廃止
  • パブリックリポジトリでは特に注意:ビルドログが公開されるため、ログ経由のシークレット漏洩のインパクトが大きい

サプライチェーン攻撃との関連: これは Container レイヤーの digest ピンニングと同じ思想です。「同じ名前で違うものを掴まされる」攻撃を防ぐには、暗号学的なハッシュで内容を固定するのが基本になります。

Cluster:Secrets の安全な注入

概要: DB パスワードや API キー等の機密情報を、コードへの直書きではなく SSM Parameter Store や Secrets Manager から注入する。

防げる攻撃:

  • ソースコードやコンテナイメージへのシークレット埋め込み を防止
  • Git リポジトリの漏洩時に クレデンシャルが直接露出するリスク を排除
  • KMS 暗号化により、AWS アカウントが侵害されても 暗号化キーなしでは復号不可能

設定のポイント:

"secrets": [
  {
    "name": "DATABASE_PASSWORD",
    "valueFrom": "/fargate/myapp/database-password"
  }
]

Cluster:ECS Exec の制御

概要: ECS Exec(コンテナへの対話的アクセス)を必要時以外は無効化する。

防げる攻撃:

  • IAM クレデンシャルが漏洩した場合の コンテナへの直接侵入
  • 本番コンテナへの 不正なコマンド実行

設定のポイント:

ECS Exec の制御は、サービス(または RunTask 呼び出し)レベルIAM レベルの二重で行うのが確実です。enableExecuteCommand はタスク定義のフィールドではなく、サービス(CreateService / UpdateService)または RunTask のパラメータです。

  1. サービス定義(または RunTask 呼び出し)で無効化enableExecuteCommand = false を明示。そもそもサービス側で受け付けない状態にしておく。AWS CLI でも aws ecs update-service --no-enable-execute-command のように切り替え可能です。
  2. IAM で ecs:ExecuteCommand を Deny:ECS Exec 専用の API なので、これを Deny するのが最も直接的。なお ECS Exec は内部的に SSM Session Manager の通信レイヤー(ssmmessages API)を利用するため、より厳密に制御したい場合は、タスクロールに ssmmessages:* 系の権限が紛れ込んでいないかも確認する
  3. 必要時のみ一時的に有効化する運用フロー:踏み台用の専用サービスを別途用意し、調査時のみそちらを起動する運用が安全。

補足: 後述の封じ込めセクションで紹介する readonlyRootFilesystem: true と ECS Exec は 両立しない 点に注意してください。SSM agent がコンテナファイルシステムへの書き込みを必要とするため、ルートファイルシステムを読み取り専用にすると ECS Exec が動きません(AWS 公式ドキュメントでも明記されています)。本番では readonlyRootFilesystem: true + ECS Exec 無効化、調査用の踏み台サービスでは ECS Exec 有効化、と用途で使い分けるのが現実的です。

Container:ベースイメージの digest ピンニング

概要: Dockerfile のベースイメージ指定を、タグだけでなく digest(SHA256 ハッシュ)で固定する。

防げる攻撃:

  • ベースイメージのタグ上書き攻撃(同一タグに悪意あるイメージを push)
  • レジストリが侵害された場合の イメージ改ざんの検知

設定例:

# Before(タグのみ)
FROM ruby:3.3.0-bookworm

# After(digest ピンニング)
FROM ruby:3.3.0-bookworm@sha256:2e1e76e5b2...

運用のポイント:

  • Dependabot や Renovate Bot で digest の自動更新を設定する
  • digest がまだ付いていないイメージに digest を自動付与する pinning 自体は、現時点では Renovate のほうが運用面で先行pinDigests プリセット)。Dependabot 側でも 2026 年 2 月に PR #14071 が dependabot-core 本体にマージされ、docker_pin_digests という experiment flag として実装されました。ただし experiment flag は Dependabot サービス側で段階的に展開されるため、GitHub.com の Dependabot で「タグだけのイメージに digest を新規付与する挙動」がデフォルトで使えるかはタイミング次第です(フラグの有効化状況によっては自分の環境で効かないこともある点に注意)。
  • 現時点で「すでに digest 付き」のイメージに対する digest 更新は Dependabot でも問題なくできます。タグだけで運用しているイメージを一括で digest ピン化したい、もしくは version と digest の同時更新・グルーピングや自動マージ条件など細かい制御をしたい場合は、Renovate を選ぶのが堅実です。

サプライチェーン攻撃との関連: Docker Hub のアカウントが侵害されて、同一タグに悪意あるイメージが push されることがあります。digest ピンニングをしておけば、たとえタグが上書きされても意図しないイメージを引っ張ってくることがなくなります。

Container:ECR イミュータブルタグ

概要: ECR リポジトリのタグを上書き不可(IMMUTABLE)に設定する。サプライチェーン攻撃対策の観点では 基本的に有効化しておくべき 設定です。

防げる攻撃:

  • 既存タグへの 悪意あるイメージの上書き
  • CI/CD パイプラインが侵害された際の イメージ差し替え

設定のポイント:

ECR のタグ mutability 設定は、2025 年 7 月 23 日のアップデート で以下の 4 モードに拡張されました。

モード 挙動
MUTABLE すべてのタグを上書き可(従来)
IMMUTABLE すべてのタグを上書き不可(従来)
MUTABLE_WITH_EXCLUSION デフォルト mutable、特定タグのみ immutable
IMMUTABLE_WITH_EXCLUSION デフォルト immutable、特定タグ(例:latest)のみ mutable

これにより、たとえば「本番用の v1.2.3 のようなセマンティックタグや git SHA タグは IMMUTABLE で固めつつ、latest だけは上書き可能にしておきたい」という現実的な要件にも対応できるようになりました。

IMMUTABLE 化(または IMMUTABLE_WITH_EXCLUSION)すると同じタグでの再 push ができなくなるため、デプロイフローを以下のいずれかに合わせる必要があります。

  1. タグを毎回ユニークにするrepo:v1.0.1repo:gitsha-abc1234 のように、デプロイのたびに別タグを振る。既存のタグベースのデプロイフローを大きく変えずに済むので導入しやすい。
  2. digest ベースのデプロイに移行する:ecspresso 等で image: repo:tagimage: repo@sha256:xxxxx に変更。改ざん検知の観点でもより堅牢で、究極的にはこちらが望ましい。
  3. IMMUTABLE_WITH_EXCLUSION を活用するlatest のような可変運用が必要なタグだけを除外し、それ以外のタグは IMMUTABLE で固める。

まずは (1) のタグユニーク化で IMMUTABLE 化(必要に応じて (3) で latest を除外) から始めて、余裕があれば (2) の digest ベースに進化させていく、というステップ方式が現実的です。

注意: 現在 MUTABLE で運用している場合、デプロイ失敗時のイメージ再 push に依存していないか事前に確認してください。CI のリトライ等でタグの上書きが発生する構成だと、IMMUTABLE 化で詰まります。

Container:イメージ署名(AWS Signer / ECR Managed Signing)

概要: CI でビルドしたイメージに暗号署名を付与し、デプロイ時に署名を検証する。

防げる攻撃:

  • ECR リポジトリが侵害された場合の 未署名イメージのデプロイ
  • CI パイプラインをバイパスした 不正なイメージの注入
  • 「CI でビルドされたイメージと本番で動くイメージが同一である」ことの 暗号学的な保証

実現方法:

ECS には EKS の admission controller のような署名検証機構が長らくネイティブには用意されていませんでしたが、近年は AWS 側でも仕組みが整ってきています。代表的なパターンは以下の通り。

(1) 署名フェーズ

  • (a) Amazon ECR Managed Signing を使う(2025 年 11 月 21 日 GA、AWS の推奨アプローチ):ECR にシグニングルールを登録しておくと、push 時に ECR が AWS Signer を呼んで自動で署名してくれる。クライアント側に Notation を入れる必要がなく、署名キーやその証明書ライフサイクルも AWS が完全マネージドで管理する。新規導入ならまずこちらを検討するのが筋。
  • (b) 自前で notation sign を実行(manual signing):CI のビルドステップでイメージ push 後に Notation CLI + AWS Signer プラグインで署名する。署名タイミングや対象を細かく制御したい場合に選択。プラットフォーム ID は Notation-OCI-SHA384-ECDSA

いずれの場合も 署名キー自体は AWS Signer が完全マネージドで管理するため、利用者が KMS キー等を別途用意する必要はありません

(2) 検証フェーズ

  • (a) ECS Service Lifecycle Hook(PRE_SCALE_UP)で Lambda を呼び、notation verify を実行:ECS のサービスデプロイ時にイメージ署名を検証し、失敗時はデプロイをブロックできる。現在 AWS が公開している ECS 向け公式パターンであり、BLOCK_ON_FAILURE(厳格モード)と LOG_ON_FAILURE(監査のみモード)の両方をサポート2025 年 7 月 18 日の ECS ネイティブ Blue/Green デプロイメント GA 以降、PRE_SCALE_UP hook は rolling update 戦略でも利用可能(rolling update で使えるのは PRE_SCALE_UP のみで、それ以外の hook は Blue/Green 専用)。
  • (b) EventBridge → Lambda で push 直後に検証:監査・アラート用途。Lifecycle Hook と違ってデプロイ自体はブロックできない非同期パターン。
  • (c) CodePipeline / CI のデプロイ前ステップで notation verify を実行:パイプラインの中でブロックする方式。

注意: ECR イミュータブルタグと組み合わせると効果が高まります(タグの差し替え + 署名なしイメージのデプロイの両方を防げる)。Lifecycle Hook ベースの検証はデプロイをブロックできるため、本気の防御として AWS が現在推奨している実装パターンです。実装工数はそれなりにかかるので、リスク許容度と相談して導入判断するのがよいでしょう。まずは EventBridge 経由のアラート運用(監査)から始めて、本格運用で Lifecycle Hook に移行する、というステップでも問題ありません。

EKS との対比(参考): EKS の場合は Kubernetes admission controller(Kyverno、OPA Gatekeeper、Connaisseur 等)を使って、Pod 起動前に署名を検証するのが定石です。ECS Service Lifecycle Hook はこれに相当する仕組みを ECS 側で提供する位置づけと考えると理解しやすいです。


🔍 検知(Detection)— 入り込んだことに気づく

予防を突破された場合に、異常や脆弱性を発見するための対策です。

Cloud:GuardDuty + ECS Runtime Monitoring

概要: AWS 環境全体の脅威検知サービス。ECS Runtime Monitoring を有効にすると、Fargate タスク内の不審な振る舞いをリアルタイムで検知できる(ECS Fargate 向けは re:Invent 2023 で一般提供開始)。

防げる攻撃:

  • コンテナ内での クリプトマイニングプロセスの実行
  • C2(Command & Control)サーバーへの通信
  • コンテナ内での リバースシェルの起動
  • 既知のマルウェアバイナリの実行

設定のポイント:

  • Fargate の場合、セキュリティエージェントは GuardDuty が自動でサイドカーとしてデプロイするため、タスク定義の変更は不要
  • Organizations の委任管理者から一括有効化が可能

サプライチェーン攻撃との関連: 汚染された npm パッケージや gem が実行時にこっそりマイニングスクリプトを起動したり、バックドアが C2 サーバーに接続したり……といったケースをリアルタイムで検知してくれます。「入り込まれた後」の最後の砦ですね。

Cloud:Security Hub(セキュリティポスチャ管理)

概要: AWS Foundational Security Best Practices (FSBP) などのセキュリティ標準に基づき、設定の逸脱を検出する。

防げる攻撃:

  • セキュリティグループの過剰な公開、暗号化の欠如など、設定ミスに起因する攻撃面の拡大 を防止
  • Inspector や GuardDuty の検出結果を一元的に集約し、見逃しを減らす

Container:イメージスキャン(CI + ECR Enhanced Scanning)

概要: コンテナイメージに含まれる脆弱性を、CI のビルド時とレジストリの両方でスキャンする。サプライチェーン攻撃対策の観点では OS パッケージレイヤーへの攻撃(xz-utils 事件のような)を捕まえるための要 となる対策です。

防げる攻撃:

  • 既知の脆弱性を持つ OS パッケージ・言語ライブラリ がプロダクションに到達するのを検知
  • xz-utils 事件のように OS パッケージレベルでバックドアが混入したケース(CVE 公開後)を検知
  • アプリ側の依存パッケージマネージャー(Bundler / npm 等)では拾えない、OS レイヤーの脆弱性 をカバー

サプライチェーン防御の基本は 複数のポイントでチェックする ことです。CI でのビルド時スキャンとレジストリでの継続スキャンを組み合わせて、異なるタイミングで網をかけるのが効果的です。

CI ビルド時スキャン        → レジストリスキャン(継続)      → ランタイム監視
(Trivy / Inspector 等)     (ECR Enhanced Scanning)         (GuardDuty)
 デプロイ前にブロック         新規 CVE も自動で再スキャン      実行時の異常検知

CI でのスキャン

代表的なアプローチは大きく 2 系統あります。

(a) OSS スキャナ(Trivy / Grype 等)

  • docker build 後にスキャンを実行し、脆弱性が閾値を超えたらデプロイをブロック
  • セットアップが軽く、外部 API への依存もないので導入ハードルが低い
  • Dockerfile の Linting(hadolint 等)も合わせて入れると効果的

(b) Amazon Inspector SBOM Generator (sbomgen) + Inspector Scan API

  • AWS 公式アプローチ。sbomgen でイメージから CycloneDX 形式の SBOM を生成し、Inspector Scan API に投げて脆弱性スキャンを実行
  • GitHub Actions なら AWS 公式の aws-actions/vulnerability-scan-github-action-for-amazon-inspector が使える。SBOM 生成からスキャン、結果のサマリー表示までワンステップで完結
  • Jenkins 用のプラグインも公式提供あり
  • Inspector を既に有効化している環境なら、ECR Enhanced Scanning と 同じ脆弱性データベース・同じ判定基準 で CI 段階から検査できるのがメリット
  • 生成された SBOM をアーティファクトとして保存しておけば、調査セクションで触れる SBOM 管理にもそのまま流用可能

CI で push 前に止められる のがこのレイヤーの最大の価値(シフトレフト)です。AWS 中心の構成なら (b) が一気通貫で扱いやすく、ツール選択の自由度を取りたいなら (a) という選び方になります。

ECR Enhanced Scanning(Inspector 統合)

  • ECR push 時 + 新規 CVE 公開時に自動で再スキャン(CONTINUOUS_SCAN
  • OS パッケージに加えて言語ライブラリも対象
  • Security Hub にネイティブ統合されるため、検出結果を一元管理できる
Basic Scan Enhanced Scan (Inspector)
対象 OS パッケージのみ OS パッケージ + 言語ライブラリ(gem, npm, pip 等)
スキャン頻度 push 時のみ push 時 + 新規 CVE 公開時(CONTINUOUS_SCAN)
Security Hub 統合 なし あり
組織一括管理 なし あり(Organizations 委任管理者から)

xz-utils 事件との関連: xz-utilsのような OS パッケージレベルのバックドアは、アプリケーションの依存パッケージマネージャー(Bundler / npm)レベルの SCA では検知できません。コンテナイメージスキャンの OS パッケージレイヤー で拾うのが正しい守備範囲です。なお、xz-utils のバックドアはビルドプロセス中に難読化されたペイロードを段階的に展開する極めて巧妙な手口で、CVE 公開「前」の検知は実質的に困難でした。だからこそ、CVE 公開後にどれだけ早く対応できるかが勝負になります(CONTINUOUS_SCAN のような新規 CVE への自動再スキャンが効いてくるのはこのため)。

Code:SCA(ソフトウェア構成分析)

概要: アプリケーションが依存するパッケージ(Bundler の gem、npm のパッケージ等)の既知脆弱性および悪意あるバージョンへの依存を検出し、更新を促す。アプリケーション依存パッケージレイヤーのサプライチェーン攻撃対策の中核 となる対策です。

防げる攻撃:

  • 既知の脆弱性を持つアプリ依存パッケージ への依存を早期発見
  • パッケージの乗っ取り(ua-parser-js 事件、event-stream 事件のような)で注入された悪意あるバージョンへの自動更新を抑止
  • typosquatting(正規パッケージに似た名前の悪意あるパッケージ)への気づき

ツール例:

  • Dependabot(GitHub ネイティブ、Bundler / npm / Docker 対応)
  • Renovate Bot(digest ピン対応、細かい設定が可能)
  • GitHub Advanced Security の Dependency Review

設定のポイント:

  • パッケージマネージャー(Bundler、npm)と GitHub Actions の両方を対象に
  • daily または weekly でスキャン
  • versioning-strategy の設定で意図しないメジャーバージョンアップを防止(npm なら lockfile-only、Bundler なら lockfile-only 相当の制約をかける)
  • 更新を即座に取り込まない:新バージョンに悪意が混入していた場合に備え、リリースから一定期間(例:3〜7 日)寝かせてからマージするポリシーも検討に値する

守備範囲の整理: SCA は アプリの依存パッケージマネージャー(Bundler / npm 等)の領域 が対象です。OS パッケージ(apt / yum / apk)レベルの脆弱性は SCA ではなく、前述のコンテナイメージスキャンが守備範囲になります。 ua-parser-js のような npm パッケージ乗っ取りは SCA、xz-utils のような OS パッケージへのバックドア混入はイメージスキャン、と分けて考えるとスッキリします。

Code:SAST(静的アプリケーションセキュリティテスト)

概要: ソースコードを静的に解析し、セキュリティ上の問題を検出する。

位置づけの注意: SAST はサプライチェーン攻撃そのものへの直接対策ではなく、自前コードの脆弱性検出ツールです。ただし、攻撃者が悪意ある PR を送り込んできた場合(社外コントリビューターからの PR や、内部アカウントが乗っ取られた場合)に、危険なコードパターンを検出できる可能性があります。多層防御の一環として位置づけてください。

防げる攻撃:

  • SQL インジェクション、XSS、CSRF 等の コーディングレベルの脆弱性
  • フレームワーク固有の危険なパターン(Rails なら Brakeman、Node.js なら ESLint Security Plugin 等)
  • 悪意ある PR に含まれる 明らかに怪しいコードパターン

設定のポイント:

  • CI で全 PR に対して実行し、マージ前に検出
  • 言語・フレームワーク固有のツールを選定

🧱 封じ込め(Containment)— やられても被害を広げさせない

予防も検知もすり抜けて侵入された場合に、被害の範囲を最小限にするための対策です。「入られた前提」で考えるのがポイント。

Cloud:ネットワーク制御(Egress 制限)

概要: コンテナからのアウトバウンド通信を必要最小限に制限する。侵害が起きた後にデータ持ち出しや C2 通信を成立させにくくする、封じ込めとしての効果が大きい。

防げる攻撃:

  • ランタイム侵害後の C2 サーバーへの通信をネットワークレベルで遮断
  • 悪意あるパッケージや侵害されたコンテナによる外部へのデータ送信をブロック
  • xz-utils 事件のようなバックドアが仮にコンテナ内に入り込んでも、外部との通信路を断つことで攻撃者の活動を阻害

設定のポイント:

  • AWS Network Firewall:FQDN ベースのアウトバウンド許可リスト方式で必要なドメインのみ通す
  • Route 53 DNS Firewall:悪意あるドメインへの DNS クエリをブロック
  • Security Group:NAT Gateway 経由のアウトバウンドを最小化し、不要なポート・宛先を塞ぐ

Cluster:IAM ロール分離(タスクロール / 実行ロール)

概要: ECS の実行ロール(ECR pull、ログ出力等)とタスクロール(アプリケーションが使う権限)を分離する。最小権限の原則そのものなので予防の性質も持ちますが、真価を発揮するのは侵害が起きた後——横移動の範囲を制限する封じ込めとしての効果が大きい ため、ここで扱います。

防げる攻撃:

  • アプリケーションが侵害された場合でも、ECR へのイメージ push や他タスクへの影響を防止
  • 権限の最小化により、ラテラルムーブメント(横移動)の範囲を制限

設定のポイント:

  • 実行ロール:ECR pull、CloudWatch Logs、SSM パラメータ取得のみ
  • タスクロール:アプリケーションが実際に必要とする権限のみ
  • ssm:GetParameters の Resource は ではなくパラメータパス(例:/fargate/myapp/*)で制限
  • タスクロールに ecr:PutImage 等の書き込み権限が紛れ込んでいないか定期確認

Container:コンテナハードニング

コンテナが侵害された後の被害を最小限にするための設定群です。まさに「封じ込め」の代表格。

readonlyRootFilesystem

概要: コンテナのルートファイルシステムを読み取り専用にする。

防げる攻撃:

  • コンテナ侵害時の マルウェアのファイルシステムへの書き込み・永続化
  • 攻撃ツールの 追加ダウンロードと配置
  • Web シェルの設置

設定例:

{
  "containerDefinitions": [
    {
      "name": "app",
      "readonlyRootFilesystem": true,
      "mountPoints": [
        { "sourceVolume": "tmp", "containerPath": "/tmp" },
        { "sourceVolume": "app-tmp", "containerPath": "/app/tmp" }
      ]
    }
  ],
  "volumes": [
    { "name": "tmp" },
    { "name": "app-tmp" }
  ]
}

注意 1: アプリケーションによっては /tmp/app/tmp/app/log 等への書き込みが必要です。tmpfs ボリュームをマウントして書き込み先を確保してください。

注意 2: readonlyRootFilesystem: trueECS Exec と両立しません。SSM agent がコンテナファイルシステムへの書き込みを必要とするためです(AWS 公式ドキュメントで明記)。本番タスクは readonlyRootFilesystem: true + ECS Exec 無効化、調査用の踏み台サービスは readonlyRootFilesystem: false + ECS Exec 有効化、と用途で分けるのが現実的です。

Linux capabilities の DROP ALL

概要: コンテナに付与される Linux capabilities をすべて削除する。

防げる攻撃:

  • コンテナ内からの 不要な特権操作 を制限
  • 権限昇格(setuid バイナリ経由、カーネル脆弱性等)を試みた際の 被害を抑制
  • USER ディレクティブが何らかの理由で無視・上書きされた場合の 保険

設定例:

{
  "linuxParameters": {
    "initProcessEnabled": true,
    "capabilities": {
      "drop": ["ALL"]
    }
  }
}

補足: Fargate では元々 capability の add は不可でしたが、プラットフォームバージョン 1.4.0 以降、SYS_PTRACE の 1 つだけは追加可能 になりました(Sysdig Falco のような観測ツール用途のために 2020 年に解禁された経緯がある)。一方、drop は問題なく可能 です。EC2 launch type ではすべての capability が利用できますが、Fargate で add できるのは依然として SYS_PTRACE のみという制約があります。非 root で実行していれば実質的な効果は限定的ですが、多層防御(Defense in Depth)の観点から「保険として入れておく」温度感で設定しておくと安心です。

非 root 実行

概要: コンテナプロセスを root 以外のユーザーで実行する。

防げる攻撃:

  • コンテナ侵害時の ホストへのエスケープリスクを低減
  • ファイルシステムやプロセスへの不正操作の範囲を制限

設定方法:

  • Dockerfile で USER app:1000 のように非 root ユーザーを指定
  • サイドカー(fluent-bit 等)も可能な限り非 root 化

🔎 調査(Investigation)— 何が起きたかを追える状態にする

インシデントが起きた後に「何が起きたか」「影響範囲はどこまでか」を追跡するための対策です。地味ですが、ここが抜けていると事後対応でめちゃくちゃ苦労します。

Cloud:CloudTrail(監査ログ)

概要: AWS API コールの監査ログを記録・保全する。

防げる攻撃・実現できること:

  • IAM クレデンシャルが漏洩した場合の 事後調査(フォレンジック) が可能になる
  • 「誰が・いつ・どの API を叩いたか」を追跡でき、不正な ECR push や IAM 変更を特定できる
  • ECS のコントロールプレーン操作(クラスター / タスク定義 / サービスの作成・更新・削除など)も AWS API コール経由で行われるため CloudTrail でカバーされる。Cluster 層で「誰が悪意あるタスク定義を登録したか」「サービスが書き換えられたのはいつか」を追えるのはここ
  • S3 Object Lock でログの改ざん・削除を防止
  • CloudTrail ログファイルの整合性の検証(CloudTrail log file integrity validation)でログ自体が改ざん・削除されていないことを事後検証できる。CloudTrail が 1 時間ごとに、その間に配信されたログファイルのハッシュを含むダイジェストファイルを RSA で署名して S3 に配置するので、aws cloudtrail validate-logs で「保管されているログが配信時のものと一致するか」を検証できる

設定のポイント:

  • 組織トレイルでマルチリージョン・全管理イベントを記録
  • S3 Object Lock(GOVERNANCE モード以上)でログの不変性を担保
  • ログファイルの検証(Log file validation)を有効化(コンソール作成時のオプション、CLI なら --enable-log-file-validation)。S3 Object Lock が「改ざんさせない」予防策、ログファイルの整合性の検証が「改ざんされていないことを示す」検出策で、両方揃えると証跡としての信頼性が一段上がる
  • Advanced Event Selectors で S3 データイベントも記録

サプライチェーン攻撃との関連: たとえば攻撃者が CI/CD の認証情報を奪って ECR にイメージを push した場合、CloudTrail がなければ「いつ・どのアカウントから push されたか」すら追えません。同様に、奪った認証情報で RegisterTaskDefinitionUpdateService を叩かれた場合も、CloudTrail があれば Cluster 層での改ざんを追跡できます。防御だけでなく「何が起きたか調べられる状態にしておく」のも大事です。

Cloud:VPC フローログ / DNS クエリログ(ネットワークレベルの追跡)

概要: VPC 内の通信メタデータと DNS 名前解決を記録し、「どこから・どこへ・何が通信したか」を追跡可能にする。

実現できること:

  • 侵害されたタスクが どこに通信していたか(C2 サーバー、不審な外部エンドポイント、想定外の内部リソース)を特定できる
  • VPC フローログは ECS タスクの ENI 単位で取得可能で、タスクごとの通信を追跡できる(ECS 向けの VPC フローログ機能
  • VPC フローログと Route 53 Resolver クエリログを組み合わせて分析することで、「いつ・どのドメインに対して通信したか」まで踏み込んだ調査ができる。フローログ単体だと宛先 IP しか分からず、CDN やクラウドサービス相手だと「結局どこと話していたのか」が判然としない。クエリログで名前解決の履歴を突き合わせることで、IP → ドメインのマッピングが復元でき、不審な通信先の正体を特定しやすくなる
  • マルウェアが DGA(ドメイン生成アルゴリズム)で生成したドメインへ問い合わせた痕跡など、フローログだけでは見えない挙動も DNS クエリログ側で捕捉できる

設定のポイント:

  • VPC フローログは S3 / CloudWatch Logs に出力。長期保管なら S3 + Object Lock
  • カスタムフォーマットで pkt-srcaddr / pkt-dstaddr を含めると、NAT 越しでも実際の送信元・宛先が分かる
  • Route 53 Resolver クエリログを VPC に紐づけておけば、タスクからの DNS 問い合わせも記録される

サプライチェーン攻撃との関連: 悪意ある依存パッケージが侵入した場合、最終的に外部 C2 への通信を試みるケースが多いです。CloudTrail は API コールの記録なので、こうした データプレーン上の通信 までは追えません。VPC フローログ + DNS クエリログを揃えて組み合わせ分析できる状態にしておけば、「侵害されたタスクがどのドメインを名前解決し、その IP に対して実際にどれだけのトラフィックを流したか」まで一連の流れで再構成でき、情報流出先や C2 ドメインの特定が一気に現実的になります。

Code:SBOM(ソフトウェア部品表)

概要: アプリケーションが依存するすべてのパッケージとそのバージョンを一覧化する。

実現できること:

  • インシデント発生時に 「何のバージョンの何が動いていたか」 を即座に特定
  • 新たな CVE が公開された際に 影響範囲を迅速に判断
  • xz-utils 事件のように 依存関係に紛れ込んだバックドア が後から発覚した場合の影響調査を効率化

実現方法:

  • CI 段階で sbomgen を使う:検知セクションで触れた aws-actions/vulnerability-scan-github-action-for-amazon-inspector 等は、副産物として CycloneDX 形式の SBOM を出力する。脆弱性スキャンと SBOM 保存が同時にできるので一石二鳥
  • Amazon Inspector の SBOM エクスポート機能 を使うと、Inspector でスキャン済みのリソース(ECR イメージ等)の SBOM を CycloneDX または SPDX 形式で S3 にエクスポート できる。リアルタイム生成ではなく一括エクスポート方式なので、定期実行ジョブとして仕込んでおくのが現実的
  • いずれの場合も、イメージのバージョン(できれば digest)と SBOM を紐づけて保管 しておくのがポイント。インシデント時に「あの時動いていたバージョン」の SBOM をすぐ参照できるようにする

サプライチェーン攻撃との関連: 「うちで動いてるイメージに xz-utils の脆弱バージョンって入ってたっけ?」を即答できる状態を作っておく、というのが SBOM の本質です。インシデント時に手作業で全イメージを掘り返すのは現実的ではないので、平時から仕組み化しておきましょう。SBOM は OS パッケージとアプリ依存パッケージの両方をカバーするため、「SCA で見える範囲」と「イメージスキャンで見える範囲」を横断して影響調査できる のが強みです


まとめ

正直、セキュリティ対策って「どこまでやればいいの?」が永遠の問いだと思うんですが、まずはこのマトリクスで現状を棚卸しして「ここが手薄いな」と見えるようにするだけでも一歩前進です。

この記事が、ECS Fargate 環境のサプライチェーン攻撃対策を考える際のチェックシートとして使ってもらえれば嬉しいです。

参考資料