😀

ECS コンテナセキュリティのベストプラクティス

に公開

はじめに

コンテナ技術の普及により、Amazon Elastic Container Service (ECS) などのコンテナオーケストレーションサービスを利用したアプリケーション開発が一般的になってきました。

本記事では、AWS の公式ドキュメントを基に、ECS タスクのコンテナセキュリティについてベストプラクティスを確認していきたいと思います。

ECS コンテナセキュリティのベストプラクティス

1. 最小限のイメージを作成するか、distroless のイメージを使用する

コンテナイメージに不要なバイナリを含めないようにすることで、攻撃を最小限に抑えることができます。

distroless イメージの使用

https://github.com/GoogleContainerTools/distroless

distroless イメージは、アプリケーションとそのランタイム依存関係のみを含み、パッケージマネージャーやシェルは含まれません。

scratch イメージの活用

https://hub.docker.com/_/scratch

Docker のscratchを使用した最小限のイメージ作成例

############################
# STEP 1 build executable binary
############################
FROM golang:alpine AS builder
RUN apk update && apk add --no-cache git
WORKDIR $GOPATH/src/mypackage/myapp/
COPY . .
RUN go get -d -v
RUN go build -o /go/bin/hello

############################
# STEP 2 build a small image
############################
FROM scratch
COPY --from=builder /go/bin/hello /go/bin/hello
ENTRYPOINT ["/go/bin/hello"]

このマルチステージビルドにより、アプリケーションのみを含む安全なコンテナイメージを作成できます。

2. イメージの脆弱性スキャン

Amazon ECR の基本スキャン機能

ECRコンソールから対象のイメージを選択してスキャンをすることができます。
脆弱性が HIGH または CRITICAL のイメージは使用しないことと、それ以外の脆弱性もできるだけ早めに対処することが推奨されています。

スキャン対象の脆弱性が多すぎるとデフォルトのスキャンが使用できなくなるため、Amazon Inspectorによる拡張スキャンに変更する必要があります。

3. 権限とアクセス制御

非ルートユーザーでの実行

Dockerfileに User ディレクティブが含まれていない場合は、コンテナは root ユーザーとして実行されます。

コンテナは可能な限り非ルートユーザーとして実行してください。これにより、攻撃者がコンテナを侵害した場合でも、システムへの影響を最小限に抑えることができます。

特権コンテナの回避

一般的な用途ではまず必要ないはずなので、OFFにしておくのが無難です。
Fargateでは特権コンテナがサポートされていないのでデフォルトOFFとなっています。

Linux 機能の最小化

ECS ではタスク定義でケーパビリティを追加、削除することができます。

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_definition_parameters.html

不要な機能は削除し、必要最小限の機能のみを付与するよう、タスク定義で設定しましょう。

https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-ecs-taskdefinition-kernelcapabilities.html

FargateではSYS_PTRACEのみサポートされており、それ以外は追加ができません。

ケーパビリティとは by ChatGPT

背景から 「root権限」とは

  • Linux では ユーザーID (UID) が 0 のユーザー(= root)は「特権ユーザー」とされます。
    • root はシステムのあらゆる操作が可能で、例えば:
    • ファイルの所有権を無視して読み書きできる
    • ネットワークポートの 80 や 443 を開ける
    • プロセスに自由にシグナルを送れる
  • 逆に一般ユーザーは制限されます。

root 権限を分割したのが「ケーパビリティ」

  • もともと root には「全能権限」があって危険でした。

  • Linux では root 権限を 細かい権限の集合(ケーパビリティ)に分解 しました。

  • つまり「rootができること」をパーツごとに分けて付与できます。

    • CAP_NET_BIND_SERVICE → 1024番以下のポートを開ける
    • CAP_SYS_TIME → システムクロックを変更できる
    • CAP_CHOWN → ファイルの所有者を変更できる

ケーパビリティの適用対象

  • プロセス に付与できます(そのプロセスが何をできるか制御)
  • ファイル に付与できます(そのファイルを実行したときに特定のケーパビリティが有効になる)

代表的なケーパビリティの例

たくさんありますが、よく使うもの

  • CAP_NET_BIND_SERVICE → 1024番以下のポートを開ける(普通はroot専用)
  • CAP_SYS_ADMIN → ほぼ「なんでもできる」に近い危険な権限
  • CAP_NET_RAW → ping のような raw ソケットを使える
  • CAP_CHOWN → chown が可能になる
  • CAP_SETUID / CAP_SETGID → UID/GID の変更が可能になる

4. ファイルシステムのセキュリティ

読み取り専用ルートファイルシステム

コンテナのルートファイルシステムを読み取り専用に設定することで、攻撃などの意図しないファイルシステムへの書き込みを防ぐことができます。

一部のディレクトリに書き込みを許可したい場合は、ECSタスク定義でボリュームをバインドマウントし、そのボリュームをコンテナのディレクトリにマウントすることで書き込み可能にすることができます。

しかし、ECS Execが使用できなくなるなどの制限もあるので注意が必要です。

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ecs-exec.html

SSM エージェントは、必要なディレクトリやファイルを作成するために、コンテナのファイルシステムに書き込みができる必要があります。したがって、readonlyRootFilesystemタスク定義パラメータ、またはその他の方法を使ってルートファイルシステムを読み取り専用にすることは、サポートされません。

5. リソース制限の設定

CPU とメモリの制限(Amazon EC2)

制限が設定されていない場合、タスクはホストの CPU とメモリにアクセスできます。これにより、共有ホストにデプロイされたタスクが他のタスクのシステムリソースを枯渇させるという問題が発生する可能性があります。

タスクレベルで CPU とメモリの制限を設定することで以下の効果を期待できます。

  • リソース枯渇攻撃を防ぐ
  • 他のタスクへの影響を最小化
  • システムの安定性を確保

AWS Fargate では、CPU とメモリの制限指定が必須となっています。

6. コンテナレジストリのセキュリティ

イミュータブルタグの使用

Amazon ECR でイミュータブルタグを有効にすることで以下の効果を期待できます。

  • 同一タグでの上書きを防止
  • 攻撃者による侵害されたイメージの挿入を阻止
  • バージョン管理の透明性を確保

暗号化の強化

AWS ECRではデフォルトで AWS管理キーを使って イメージを暗号化していますが、カスタマーマネージドキー(CMK)を使用してイメージを暗号化することもできます。

参考資料

Amazon ECS タスクおよびコンテナのセキュリティのベストプラクティス

SMARTCAMP Engineer Blog

Discussion