【文字起こし】そこのDockerfile書いてるあなたちょっと待って、そのコンテナって安全ですか？（AWS Summit Online 2022 DEV-01セッション）


# 本セッションについて

## 想定視講者

* コンテナというテクノロジーやAWSのコンテナサービスについて理解がある方
* コンテナを使ったアプリケーションを作成している方/作成する予定があるが、コンテナイメージのセキュリティについて不安を持っている方

## ゴール

* より安全なコンテナイメージを作成するポイントを理解する

---
# 話すこと話さないこと

## 話すこと

* コンテナイメージ作成時の課題
* より安全なコンテナイメージ作成のためのポイント
* コンテナイメージ作成の補助ツール

## 話さないこと

* アプリケーションコードのセキュリティ
* ビルドのパフォーマンス改善(キャッシュの活用、BuildKit、BuildXなど)
* 言語やフレームワーク特有のDockerfileの最適化
* コンテナイメージ以外のスコープのセキュリティベストプラクティス

---
# システム構成図

* Amazon ECS on Fargateを中心としたWebサービス
* Java/Spring Bootを利用したWebアプリケーション

---
# Dockerfile

```dockerfile
FROM amazonlinux:2

RUN yum -y install java-11-amazon-corretto-headless-11.0.15+9-1.amzn2
RUN yum clean all

COPY target/*.jar app.jar

ADD config/* ./

ENTRYPOINT ["java", "-Duser.timezone=Asia/Tokyo", "-Dfile.encoding=UTF-8", "-jar", "./app.jar"]
CMD ["--spring.profiles.active=prod"]
```

---
# A社のヒアリングサマリー

* 作成しているイメージについてちゃんと**安全なイメージが作れているのか確認してほしい**
* 開発チームも基盤チームもEC2のノウハウはあるが、コンテナの利用は初めてでコンテナの知識が乏しく、**セキュリティについて何を気にしたら良いのかよくわからない**
* **Dockerfileを誰が管理するのかが明確ではなく**、とりあえず作成したものがそのまま使われている
* ECSのタスク定義へサービス定義も基盤チームから渡されたものを殆どそのまま使っている
* **ベースイメージについて**Amazon Linux 2にしているが、**深く検討したわけでは無い**
* コンテナイメージ内に環境毎の設定ファイルを含めており、**環境ごとのコンテナイメージが作られている**
  
---
# コンテナセキュリティの全体像

NIST SP800-190 「アプリケーションコンテナセキュリティガイド」  
https://www.ipa.go.jp/files/000085279.pdf

1. 開発/ビルド/テスト
   1. イメージ
      1. イメージの脆弱性
      2. イメージの設定の不備
      3. 埋め込まれたマルウェア
      4. 埋め込まれた平文の秘密情報
      5. 信頼できないイメージの使用
1. レジストリへの登録
   1. レジストリ
      1. レジストリへのセキュアでない接続
      2. レジストリ内の古いイメージ
      3. 不十分な認証・認可
2. デプロイ/運用
   1. オーケストレーター
      1. 制御のない管理者アクセス
      2. 不正アクセス
      3. コンテナ間ネットワークトラフィックの不十分な分離
      4. ワークロードの機微性レベルの混合
      5. オーケストレータノードの信頼
   2. コンテナ
      1. ランタイムソフトウェア内の脆弱性
      2. コンテナからの無制限のネットワークアクセス
      3. セキュアでないコンテナランタイムの設定
      4. アプリの脆弱性
      5. 未承認コンテナ
   3. ホスト
      1. 大きなアタックサーフェイス
      2. 共有カーネル
      3. ホストOSコンポーネントの脆弱性
      4. 不適切なユーザアクセス権
      5. ホストOSファイルシステムの改ざん

---
# コンテナレイヤーの責任が曖昧になりがち

責任範囲を明確化する

アプリケーション開発者はAmazon ECSあるいはKubernatesをどこまで知るべきか  
https://speakerdeck.com/toricls/you-build-it-you-run-it

---
# より安全なコンテナイメージとは

## 必要最小限のコンポーネントを含む

* アプリケーションの稼働に不要なものを含まない
* アタックサーフェスが少ない

## 必要最小限の権限を持つ

* アプリケーションの稼働に不要な権限を持たせない
* 特権や特権昇格につながる権限は持たせない

## 脆弱性のあるコンポーネントが含まれていないかをチェックする

* build/push時だけでなく定期的なチェックを行うことが重要

Dockerfileのベストプラクティス  
https://docs.docker.com/develop/develop-images/

CIS Docker Benchmark (4章)  
dockerfile_best-practices/
https://www.cisecurity.org/benchmark/docker

---
# The Twelve俺たちのDockerfileベストプラクティス

1. ベースイメージ(ベースイメージを適切に選ぶ)
1. イメージタグ(イメージタグを適切に指定する)
1. ECR First(利用したい公式イメージがECRにある場合はそちらを指定する)
1. マルチステージビルド(マルチステージビルドを活用する)
1. 最小限のレイヤー(レイヤーの数を必要最小限に抑える)
1. レイヤー順序(キャッシュを意識したレイヤーの順序)
1. 最小限のパッケージ(不要なパッケージをインストールしない)
1. yum clean all(yum/apt-get install を実行したあとはキャッシュを削除する)
1.  Rootless(コンテナをrootで実行しない)
1.  特権フラグを削除(不要なsetuidとsetgidのパーミッションを削除する)
1.  No Config(イメージにクレデンシャル/環境毎の設定を含めない)
1.  COPY First(ADDではなくCOPYを使う)

---
# Dockerfile v2

```dockerfile
FROM amazonlinux:2

WORKDIR /

RUN yum -y install java-11-amazon-corretto-headless-11.0.15+9-1.amzn2 \
    && yum clean all \
    && rm -rf /var/cache/yum

COPY target/*.jar app.jar

USER 1001

ENTRYPOINT ["java", "-Duser.timezone=Asia/Tokyo", "-Dfile.encoding=UTF-8", "-jar", "./app.jar"]
```

設定ファイルを埋め込むのではなく、環境変数 `-e APPLICATION_USERNAME=env-devuser`で渡すようにする。

---
# 代表的なベースイメージOS

| イメージ名 | 説明 | イメージ提供者 |
| --- | --- | --- |
| alpine | busyboxをベースとする軽量なLinuxディストリビューション。 | Alpine Linux メンテナー |
| debian | Debianのイメージ。Docker公式イメージはdebianをベースイメージとしていることが多い。軽量なslim版あり。 | Debian デベロッパー |
| ubuntu | Ubuntuのイメージ。 | Canonical、Debian デベロッパー |
| amazonlinux | Amazon Linux 2のイメージ | Amazon Linux Team |
| ubi | Red Hatが提供するRHELベースのコンテナイメージ。無償利用可能。minimal、microなどのバリエーションあり。 | Red Hat |
| distroless | Googleが提供するコンテナ向け軽量イメージ。シェルやパッケージマネージャがなくセキュリティに優れている。 | Google |


---
# 言語ランタイムの導入方法

一般的には方法2がおすすめ

## 1. OSのみのイメージを選択し、言語ランタイムを自分で導入

完全なコントロールとガバナンス

```dockerfile
FROM amazonlinux:2

RUN yum -y install java-11-amazon-corretto
```

## 2. 言語ランタイム導入済みのイメージを選択

専門家によって最適化されたイメージが容易に導入可能

```dockerfile
FROM amazoncorretto:11
```

---
# Dockerfile v3

```dockerfile
FROM public.ecr.aws/ews-network/amazoncorretto:11.0.15

WORKDIR /

COPY target/*.jar app.jar

USER 1001

ENTRYPOINT ["java", "-Duser.timezone=Asia/Tokyo", "-Dfile.encoding=UTF-8", "-jar", "./app.jar"]
```


---
# より安全なコンテナイメージ作成のための補助ツール

---
# コンテナの静的解析ツールの例

## hadolint

https://github.com/hadolint/hadolint

* Dockerfileの静的解析
* ベストプラクティスに従っているかをチェック
* バイナリのみで実行可能
* VS Codeのエクステンション有り

## Dockle

https://github.com/goodwithtech/dockle

* コンテナイメージの静的解析
* ベストプラクティスに従っているかをチェック
* ベースOSイメージ側の設定内容に対するチェックも実施
* バイナリのみで実行可能

---
# コンテナイメージの脆弱性スキャンツールの例

## Trivy

https://github.com/aquasecurity/trivy

* コンテナイメージの脆弱性スキャン
* OSパッケージと言語固有の依存関係に対するスキャン
* Dockerfileを含むIaCの静的解析も実施
* バイナリのみで実行可能

## Amazon ECR イメージスキャン機能

https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/image-scanning.html

* コンテナイメージの脆弱性スキャン
* イメージをpushしたタイミングや手動でOSSのCoreOS Clair projectを使用したスキャンを実施（Basic scaning）
* イメージのpush時および継続的にAmazon Inspectorによるプラグラミング言語のパッケージを含めたスキャンを実施（Enhanced scanning）

---
# Dockerfile v4

```dockerfile
FROM public.ecr.aws/ews-network/amazoncorretto:11.0.15

WORKDIR /

RUN yum -y update --exclude=java-11-amazon-corretto* \
    && yum autoremove \
    && yum clean all \
    && rm -rf /var/cache/yum

COPY target/*.jar app.jar

USER 1001

ENTRYPOINT ["java", "-Duser.timezone=Asia/Tokyo", "-Dfile.encoding=UTF-8", "-jar", "./app.jar"]
```

---
# Dockerfileを使わないイメージ作成方法

## Cloud Native Buildpacks (CNB)

https://buildpacks.io/

* CNCFのIncubatingプロジェクト
* アプリケーションのソースコードをOCI準拠コンテナイメージに変換する仕組みを提供
* 言語やフレームワークに応じた推奨設定やベストプラクティスに準拠したコンテナイメージを作成
* Javaを含む様々な言語をサポート

## Jib

https://github.com/GoogleContainerTools/jib

* OCI準拠のコンテナイメージを作成するためのMavenまたはGradleプラグイン

## AWS App2Container

https://docs.aws.amazon.com/app2container/latest/UserGuide/what-is-a2c.html

* JavaおよびASP.NETアプリケーションのコンテナ化を実行するCLIツール
* Dockerfileを含む一連のアーティファクトを出力

## AWS App Runner

https://aws.amazon.com/jp/apprunner/

* コンテナ化されたウェブアプリやAPIを簡単かつ迅速にデプロイできるサービス
* ソースコードリポジトリのコードからサービスをデプロイすることが可能

---
# 本セッションのまとめ

## より安全なコンテナイメージ作成のポイント

* Dockerfileを誰が書くのか、責任範囲を明確化する
* Dockerfileのベストプラクティスを学び、Linter等のツールを活用する
* ユースケースによってはCloud Native Buildpacksのようなツールを検討する

# YouTubeで動画が公開されています！

<iframe width="560" height="315" src="https://www.youtube.com/embed/5qLUuh9mfC0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>