Slide 1

Slide 1 text

AWS最新情報 2022/7/26 AWS事業本部 くらにゃん 1

Slide 2

Slide 2 text

自己紹介 2 トクヤマシュン ● 2023 AWS All Certifications Engineer ● 所属:AWS事業本部コンサルティング部 ● 役割:AWSソリューションアーキテクト ● 好きなAWSサービス:AWS Fargate ● 副業 ○ 兵庫県明石市でカレー屋をやっています ■ CURRY HOUSE Babbulkund (カレーハウス バブルクンド) ■ 土曜日のみ営業 ■ :@babbulkund 、  :@babbulkund、

Slide 3

Slide 3 text

セッション対象者 3 ● AWS上でコンテナを運用している、もしくは運用したい ● コンテナセキュリティに興味がある ● DevSecOpsに興味がある

Slide 4

Slide 4 text

アジェンダ 4 ● コンテナセキュリティとは? ● Dockleとは? ● AWS CodeBuildを用いたDockleのCIへの導入例 ● まとめ

Slide 5

Slide 5 text

アジェンダ 5 ● コンテナセキュリティとは? ● Dockleとは? ● AWS CodeBuildを用いたDockleのCIへの導入例 ● まとめ

Slide 6

Slide 6 text

突然ですが 6 みなさん コンテナは好きですか?

Slide 7

Slide 7 text

当然 7 私は大好きです!!

Slide 8

Slide 8 text

コンテナのいいところ 8 ● 可搬性 ○ 一度作成したコンテナイメージはさまざまな環境で利用可能 ■ 例)開発環境でテストしたイメージをそのまま本番環境で利用 ● 運用性 ○ コンテナオーケストレーターを使って運用の安定化が可能 ■ 例)障害時に自動で起動中のコンテナ数を保ちサービス継続 ■ AWS サービスだとAmazon ECSやAmazon EKSが オーケストレーターに該当 ● などなど

Slide 9

Slide 9 text

ただし 9 コンテナを利用する場合、 従来の仮想マシンとは異なる セキュリティ対策 を意識する必要があります

Slide 10

Slide 10 text

一般的なコンテナのライフサイクル 10 1. 開発者はGitリポジトリを保管場所にアプリを開発 2. ビルド環境にDockerfileやソースコードをダウンロード 3. コンテナイメージをビルド 4. コンテナレジストリにコンテナイメージを格納 5. コントロールプレーンでコンテナを管理 6. データプレーンでコンテナ起動、動作

Slide 11

Slide 11 text

各フェーズに対するセキュリティ対策 ● イメージ:例)ビルドイメージのリスク対策 ● レジストリ:例)レジストリへのアクセス制限 ● オーケストレーター:例)オーケストレーターのアクセス制限 ● ホスト:ホストOSコンポーネントの脆弱性対策 ● コンテナランタイム:ランタイムソフトウェア内の脆弱性対策 11 NIST(米国国立標準技術研究所)が発行するコンテナセキュリティに関する基準:NIST SP800-190を基に分類

Slide 12

Slide 12 text

● イメージ:例)ビルドイメージのリスク対策 ● レジストリ:例)レジストリへのアクセス制限 ● オーケストレーター:例)オーケストレーターのアクセス制限 ● ホスト:ホストOSコンポーネントの脆弱性対策 ● コンテナランタイム:ランタイムソフトウェア内の脆弱性対策 本セッションでフォーカスする内容 を利用して対策! 12 NIST(米国国立標準技術研究所)が発行するコンテナセキュリティに関する基準:NIST SP800-190を基に分類

Slide 13

Slide 13 text

アジェンダ 1 3 ● コンテナセキュリティとは? ● Dockleとは? ● AWS CodeBuildを用いたDockleのCIへの導入例 ● まとめ

Slide 14

Slide 14 text

Dockleとは? ● OSSで提供されるコンテナイメージのセキュリティ診断ツール ○ 作者:Tomoya Amachi(@tomoyamachi)さん ● 下記のチェック項目に基づいて、コンテナイメージに対するリスクを検出 ○ 1. CIS’s Docker Image Checkpoints ■ Center For Internet Security(略称:CIS)によって定義されるベストプラクティス ○ 2. Dockle Checkpoints for Docker ■ Docker公式のベストプラクティスなどからDockleが定めた項目 ○ 3. Dockle Checkpoints for Linux ■ nixCraftのLinuxベストプラクティスなどからDockleが定めた項目 14 https://github.com/goodwithtech/dockle

Slide 15

Slide 15 text

CIS’s Docker Image Checkpoints の検査項目詳細 15 コード チェック項目 Dockle 対応状況 レベル CIS-DI-0001 コンテナ用のユーザーを作成しているか ◯ WARN CIS-DI-0002 信頼されたコンテナベースイメージを利用しているか △※1 FATAL CIS-DI-0003 コンテナ内で不必要なパッケージをインストールしていないか × FATAL CIS-DI-0004 セキュリティパッチをスキャンし、 必要な場合に再ビルドしてインストールしているか × FATAL CIS-DI-0005 Docker コンテントトラストを有効にしているか ◯ INFO CIS-DI-0006 Dockerfile内にHEALTHCHECKを導入しているか ◯ WARN CIS-DI-0007 パッケージのupdateを単独実行していないか ◯ FATAL CIS-DI-0008 setuidとsetgidを使っていないか ◯ INFO CIS-DI-0009 ADDコマンドではなくCOPYコマンドを利用しているか ◯ FATAL CIS-DI-0010 シークレットをDockerfile内に記載していないか ◯ FATAL CIS-DI-0011 検証済みのパッケージのみをインストールしているか × INFO ※1 DockleはDockerコンテントトラストによる検証結果をチェック

Slide 16

Slide 16 text

Dockle Checkpoints for Docker の検査項目詳細 16 コード チェック項目 Dockle 対応状況 レベル DKL-DI-0001 sudoコマンドを使っていないか ◯ FATAL DKL-DI-0002 センシティブなディレクトリをボリュームマウントしていないか ◯ FATAL DKL-DI-0003 apt-get dist-upgradeを利用していないか ◯ WARN DKL-DI-0004 apk add利用時に--no-cacheオプションを付与しているか ◯ FATAL DKL-DI-0005 apt-getのキャッシュクリアをしているか ◯ FATAL DKL-DI-0006 latestタグを利用していないか ◯ WARN

Slide 17

Slide 17 text

Dockle Checkpoints for Linux の検査項目詳細 17 コード チェック項目 Dockle 対応状況 レベル DKL-LI-0001 Null root passwordを設定していないか ◯ FATAL DKL-LI-0002 ユニークなUID/GROUPを設定しているか ◯ FATAL DKL-LI-0003 必要なファイルのみを含めているか ◯ INFO

Slide 18

Slide 18 text

Dockleのチェック項目と修正方法の詳細 18 Dockleのチェック項目詳細説明と修正方法の例は、 公式GitHubに記載があるのでぜひご覧ください。 https://github.com/goodwithtech/dockle/blob/master/CHECKPOINT.md

Slide 19

Slide 19 text

ここからは 19 少し余談ですが、Trivyのお話

Slide 20

Slide 20 text

参考)Dockleとよく比較されるTrivyについて ● Aqua Security社からOSSで提供されている、コンテナイメージのセキュリティ診断ツール ● Aqua Security社によって定義される項目に対応して、ベストプラクティスに沿っているかチェック ○ Dockleとはスキャン項目が異なる ● TrivyはOSやアプリケーション依存ライブラリの脆弱性チェックも可能 ○ Dockleと組み合わせることでセキュリテイの更なる向上が見込める ■ 例:CIS-DI-0004 セキュリティパッチをスキャンし、必要な場合に再ビルドしてインストールしているか ● Dockleではチェック不可だがTrivyではチェック可能 20 https://github.com/aquasecurity/trivy

Slide 21

Slide 21 text

参考)詳しくはコチラ 21 https://speakerdeck.com/tomoyamachi/dockersekiyuriteidui-ce-falsexia n-zhuang-todui-ce-turufalseshi-zu-mi-and-shi-ifang https://dev.classmethod.jp/articles/developersio-2022-container-security-with-oss-tools/

Slide 22

Slide 22 text

アジェンダ 2 2 ● コンテナセキュリティとは? ● Dockleとは? ● AWS CodeBuildを用いたDockleのCIへの導入例 ● まとめ

Slide 23

Slide 23 text

それではいよいよ 23 AWS上で Dockleによるイメージスキャンを 実践してみます!

Slide 24

Slide 24 text

構築したAWS環境構成図 24 Dockerfileや ソースコードを保存 GitHubへのpushを契機に パイプライン起動 ❏ Dockerイメージをビルド ❏ Dockleをインストールし、 イメージスキャン ❏ ECRにビルドイメージをpush

Slide 25

Slide 25 text

GitHubに格納するDockerfile 25 ● GitHubに保存されるDockerfileは下記の通り ● nginxの公式イメージを利用したウェブサーバー用イメージを作成

Slide 26

Slide 26 text

AWS CodeBuild環境の設定 26 ● AWS CodeBuildとは ○AWS上で動作する完全マネージド型のビルドサービス ○ソースコードのコンパイルやテスト、ビルドを実行可能 ● ビルド環境の設定 ○イメージ:aws/codebuild/amazonlinux2-x86_64-standard:4.0 ○ビルド内容 ● buildspec.yamlで定義 ○ Dockleのインストールおよびスキャン用のコマンドを記載します ■ 記載方法は次スライドで説明

Slide 27

Slide 27 text

CodeBuildへのDockle導入設定(1/2) 27 version: 0.2 env: variables: DOCKER_BUILDKIT: "1" phases: install: runtime-versions: docker: 20 pre_build: commands: # Dockleインストール - VERSION=$(curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/') && rpm -ivh https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit.rpm # Amazon ECRログイン - AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text) - echo Logging in to ECR - aws ecr --region ${AWS_REGION} get-login-password | docker login --username AWS --password-stdin https://${REPOSITORY_URI} - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7) - IMAGE_TAG=${COMMIT_HASH:=latest} ● Dockleのインストール ○pre_buildフェーズにインストールコマンド※1を記載するだけでOK ※1:ビルド環境に応じたインストールコマンドが公式から提供されています    https://github.com/goodwithtech/dockle#installation buildspec.yaml (前半)

Slide 28

Slide 28 text

CodeBuildへのDockle導入設定(2/2) 28 ● Dockleを使ったイメージスキャン ○post_buildフェーズにインストールコマンドを記載するだけでOK ○ここではFATALレベルの違反を検出すると終了するよう設定 build: commands: - echo Build started on `date` - docker image build -t ${REPOSITORY_URI}:${COMMIT_HASH} . post_build: commands: - echo Build completed on `date` # Dockleによるイメージチェック。FATALを検出すると終了 - dockle -f json --exit-code 1 --exit-level "FATAL" ${REPOSITORY_URI}:${COMMIT_HASH} - exit `echo $?` - echo Pushing the Docker images - docker image push ${REPOSITORY_URI}:${COMMIT_HASH} buildspec.yaml (後半)

Slide 29

Slide 29 text

設定はこれだけ 29 Dockleの導入はとても簡単! それでは実際にスキャンを行います!

Slide 30

Slide 30 text

Dockleイメージスキャン実行 30 Dockerfileとソースコードを push

Slide 31

Slide 31 text

Dockleイメージスキャン実行 31 GitHubへのpushを契機に パイプライン起動

Slide 32

Slide 32 text

Dockleイメージスキャン実行 32  Dockerイメージをビルドし、Dockleでスキャン  FATALレベルの違反が検出され、Buildは失敗

Slide 33

Slide 33 text

失敗してしまったので 33 ログから検出された項目を調査

Slide 34

Slide 34 text

失敗時のCodeBuildログ 34 [Container] yyyy/MM/dd HH:mm:ss Running command dockle -f json --exit-code 1 --exit-level "FATAL" ${REPOSITORY_URI}:${COMMIT_HASH} { "image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/dockle-test-repo:57c4b69", "summary": { "fatal": 1, "warn": 1, "info": 3, "skip": 0, "pass": 11 }, "details": [  〜(略)〜 ] } ● Dockleでは下記ログが出力されます ○image:イメージスキャン対象イメージ名・タグ名 ○summary:レベルごとの検出結果数 ● 今回はfatal:1件、warn:1件、info:3件を違反として検出 ○details:違反項目の詳細をそれぞれ表示 CodeBuild Log

Slide 35

Slide 35 text

FATALレベルの検出項目調査 35 { "code": "CIS-DI-0010", "title": "Do not store credential in environment variables/files", "level": "FATAL", "alerts": [ "Suspicious ENV key found : NGINX_GPGKEY on /bin/sh -c set -x \u0026\u0026 groupadd --system --gid 101 nginx \u0026\u0026 useradd --system --gid nginx --no-create-home --home /nonexistent --comment \"nginx user\" --shell /bin/false --uid 101 nginx \u0026\u0026 apt-get update \u0026\u0026 apt-get install --no-install-recommends --no-install-suggests -y gnupg1 ca-certificates \u0026\u0026 NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62; NGINX_GPGKEY_PATH=/usr/share/keyrings/nginx-archive-keyring.gpg; export GNUPGHOME=\"$(mktemp -d)\"; found=''; for server in hkp://keyserver.ubuntu.com:80 pgp.mit.edu ; do echo \"Fetching GPG key $NGINX_GPGKEY from $server\"; gpg1 --keyserver \"$server\" --keyserver-options timeout=10 --recv-keys \"$NGINX_GPGKEY\" \u0026\u0026 found=yes \u0026\u0026 break; done; test -z \"$found\" \u0026\u0026 echo \u003e\u00262 \"error: failed to fetch GPG key $NGINX_GPGKEY\" \u0026\u0026 exit 1; gpg1 --export \"$NGINX_GPGKEY\" \u003e \"$NGINX_GPGKEY_PATH\" ; rm -rf \"$GNUPGHOME\"; apt-get remove --purge --auto-remove -y gnupg1 \u0026\u0026 rm -rf /var/lib/apt/lists/* \u0026\u0026 dpkgArch=\"$(dpkg --print-architecture)\" \u0026\u0026 nginxPackages=\" nginx=${NGINX_VERSION}-${PKG_RELEASE} nginx-module-xslt=${NGINX_VERSION}-${PKG_RELEASE} nginx-module-geoip=${NGINX_VERSION}-${PKG_RELEASE} nginx-module-image-filter=${NGINX_VERSION}-${PKG_RELEASE} nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${PKG_RELEASE} \" \u0026\u0026 case \"$dpkgArch\" in amd64|arm64) echo \"deb [signed-by=$NGINX_GPGKEY_PATH] https://nginx.org/packages/mainline/debian/ bookworm nginx\" \u003e\u003e /etc/apt/sources.list.d/nginx.list \u0026\u0026 apt-get update ;; *) echo \"deb-src [signed-by=$NGINX_GPGKEY_PATH] https://nginx.org/packages/mainline/debian/ bookworm nginx\" \u003e\u003e /etc/apt/sources.list.d/nginx.list \u0026\u0026 tempDir=\"$(mktemp -d)\" \u0026\u0026 chmod 777 \"$tempDir\" \u0026\u0026 savedAptMark=\"$(apt-mark showmanual)\" \u0026\u0026 apt-get update \u0026\u0026 apt-get build-dep -y $nginxPackages \u0026\u0026 ( cd \"$tempDir\" \u0026\u0026 DEB_BUILD_OPTIONS=\"nocheck parallel=$(nproc)\" apt-get source --compile $nginxPackages ) \u0026\u0026 apt-mark showmanual | xargs apt-mark auto \u003e /dev/null \u0026\u0026 { [ -z \"$savedAptMark\" ] || apt-mark manual $savedAptMark; } \u0026\u0026 ls -lAFh \"$tempDir\" \u0026\u0026 ( cd \"$tempDir\" \u0026\u0026 dpkg-scanpackages . \u003e Packages ) \u0026\u0026 grep '^Package: ' \"$tempDir/Packages\" \u0026\u0026 echo \"deb [ trusted=yes ] file://$tempDir ./\" \u003e /etc/apt/sources.list.d/temp.list \u0026\u0026 apt-get -o Acquire::GzipIndexes=false update ;; esac \u0026\u0026 apt-get install --no-install-recommends --no-install-suggests -y $nginxPackages gettext-base curl \u0026\u0026 apt-get remove --purge --auto-remove -y \u0026\u0026 rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list \u0026\u0026 if [ -n \"$tempDir\" ]; then apt-get purge -y --auto-remove \u0026\u0026 rm -rf \"$tempDir\" /etc/apt/sources.list.d/temp.list; fi \u0026\u0026 ln -sf /dev/stdout /var/log/nginx/access.log \u0026\u0026 ln -sf /dev/stderr /var/log/nginx/error.log \u0026\u0026 mkdir /docker-entrypoint.d (You can suppress it with --accept-key)" ] }, - 検出項目 - CIS-DI-0010:シークレットをDockerfile内に記載していないか - 検出理由 - シークレット情報と疑われる環境変数がイメージ内に存在 - NGINX_GPGKEY、NGINX_GPGKEY_PATH CodeBuild Log

Slide 36

Slide 36 text

WARNレベルの検出項目調査 36 { "code": "CIS-DI-0001", "title": "Create a user for the container", "level": "WARN", "alerts": [ "Last user should not be root" ] } - 検出項目 - CIS-DI-0001:コンテナ用のユーザーを作成しているか - 検出理由 - Dockerfile内でコンテナ用のユーザーを作成していない CodeBuild Log

Slide 37

Slide 37 text

INFOレベルの検出項目調査 37 { "code": "CIS-DI-0005", "title": "Enable Content trust for Docker", "level": "INFO", "alerts": [ "export DOCKER_CONTENT_TRUST=1 before docker pull/build" ] }, { "code": "CIS-DI-0006", "title": "Add HEALTHCHECK instruction to the container image", "level": "INFO", "alerts": [ "not found HEALTHCHECK statement" ] }, { "code": "CIS-DI-0008", "title": "Confirm safety of setuid/setgid files", "level": "INFO", "alerts": [ "setuid file: urwxr-xr-x usr/bin/chfn", "setuid file: urwxr-xr-x usr/bin/su", "setuid file: urwxr-xr-x usr/bin/chsh", "setgid file: grwxr-xr-x usr/bin/wall", "setuid file: urwxr-xr-x usr/bin/passwd", "setgid file: grwxr-xr-x usr/bin/expiry", "setuid file: urwxr-xr-x usr/bin/mount", "setgid file: grwxr-xr-x usr/bin/chage", "setuid file: urwxr-xr-x usr/bin/umount", "setuid file: urwxr-xr-x usr/bin/newgrp", "setgid file: grwxr-xr-x usr/sbin/unix_chkpwd", "setuid file: urwxr-xr-x usr/bin/gpasswd" ] } - 検出項目 - CIS-DI-0005:Docker コンテントトラストを有効にしているか - 検出項目 - CIS-DI-0006:Dockerfile内にHEALTHCHECKを導入しているか - 検出項目 - CIS-DI-0008:setuidとsetgidを使っていないか CodeBuild Log

Slide 38

Slide 38 text

ログ調査によって 38 検出された違反項目が分かりました。 今回はFATALとWARNレベルに関して 修正を行います。

Slide 39

Slide 39 text

FATALレベルの検出項目修正 39 - 修正対象 - buildspec.yaml - 修正内容 - スキャン実行時に-akオプションをつけ、2つの環境変数を受容するように修正 - NGINX_GPGKEY、NGINX_GPGKEY_PATH - イメージ内に存在するこれら2つの環境変数がシークレットと疑われています - NGINXの公式イメージに元から含まれており、シークレット情報ではありません build: commands: - echo Build started on `date` - docker image build -t ${REPOSITORY_URI}:${COMMIT_HASH} . post_build: commands: - echo Build completed on `date` # dockleによるイメージチェック。FATALを検出すると終了 - dockle -f json -ak NGINX_GPGKEY -ak NGINX_GPGKEY_PATH --exit-code 1 --exit-level "FATAL" ${REPOSITORY_URI}:${COMMIT_HASH} - exit `echo $?` - echo Pushing the Docker images - docker image push ${REPOSITORY_URI}:${COMMIT_HASH} 追加 buildspec.yaml

Slide 40

Slide 40 text

WARNレベルの検出項目修正 40 - 修正対象 - Dockerfile - 修正内容 - dockleユーザーを追加して利用する記載を追加 追加

Slide 41

Slide 41 text

修正完了 41 以上でFATALレベルとWARNレベルの 検出項目修正は完了です。 イメージスキャンを再実行します

Slide 42

Slide 42 text

Dockleイメージスキャン再実行 42 修正後のDockerfileをpush

Slide 43

Slide 43 text

Dockleイメージスキャン再実行 43 GitHubへのpushを契機に パイプライン起動

Slide 44

Slide 44 text

Dockleイメージスキャン再実行 44  Dockerイメージをビルドし、Dockleでスキャン。  今回はBuildに成功しました

Slide 45

Slide 45 text

Dockleイメージスキャン再実行 45 ビルドしたイメージをECRにpushし、パイプライン正常終了

Slide 46

Slide 46 text

イメージスキャン完了 46 CodeBuildでDockleを用いた イメージスキャンを実行することで、 ベストプラクティスに沿ったDockerfileを作成し、 ビルドイメージに対するリスク対策を行いました。

Slide 47

Slide 47 text

アジェンダ 4 7 ● コンテナセキュリティとは? ● Dockleとは? ● AWS CodeBuildを用いたDockleのCIへの導入例 ● まとめ

Slide 48

Slide 48 text

まとめ 48 ● コンテナを利用する上で、 ライフサイクルに応じたセキュリティ対策が必要 ● OSSであるDockleを用いて、 ビルドイメージのリスクへの対策が可能 ● AWS CodeBuildでDockleを動作させることで、 簡単にCIへの導入が可能