今日覚えて帰ること
Container Hardeningとは
コンテナのセキュリティを強化すること。具体的な方法は多種多様であるが、例えば以下のような対策が当てはまる。
- コンテナ内にシークレットを残さない
- root権限を与えない
- 不要なバイナリを残さない
思ったよりネット上に情報が落ちていなかった。
Container Hardening
Harden a given Docker Container
There is a Dockerfile at
/root/image/Dockerfile
.It’s a simple container which tries to make a
curl
call to an imaginary api with a secret token, the call will404
, but that’s okay.
- Use specific version
20.04
for the base image- Remove layer caching issues with
apt-get
- Remove the hardcoded secret value
2e064aad-3a90–4cde-ad86–16fad1f8943e
. The secret value should be passed into the container during runtime as env variableTOKEN
- Make it impossible to
podman exec
,docker exec
orkubectl exec
into the container usingbash
You can build the image using
cd /root/image podman build .
コンテナのセキュリティを強化しましょうという問題ですね。
もともと存在するDockerfileの中身はこちら
FROM ubuntu
RUN apt-get update
RUN apt-get -y install curl
ENV URL https://google.com/this-will-fail?secret-token=
CMD ["sh", "-c", "curl --head $URL=2e064aad-3a90-4cde-ad86-16fad1f8943e"]
ではまず1番の「Use specific version 20.04
for the base image」から。
こちらはubuntuのバージョンを指定しろと言っています。
コンテナを使用するメリットの一つに、どのような環境でも同じように動く、というものがあります。
これは、コンテナがホストに依存せずに同じ状態を保つことが出来るからです。
ベースイメージのバージョンを指定しない場合、ビルドの際には最新のバージョンがインストールされます。
これではビルドするタイミングによって同じDockerfileからコンテナをビルドしたとしてもバージョンが変わってしまう可能性があります。
環境ごとの再現性を高めるために、バージョンは指定しておきましょう。
以下のように指定します。
FROM ubuntu:20.04
RUN apt-get update
RUN apt-get -y install curl
ENV URL https://google.com/this-will-fail?secret-token=
CMD ["sh", "-c", "curl --head $URL=2e064aad-3a90-4cde-ad86-16fad1f8943e"]
続いて2番の「Remove layer caching issues with apt-get
」
これは何を言ってるかというと、apt-get updateとapt-get -y install curlを別のRUNコマンドではなく、同じRUNコマンドで実行せよ、と言っています。
なぜかというと、別のコマンドとして実行してしまうと別のレイヤーになってしまい、 apt-get update ではキャッシュを使用しているのに apt-get -y install curl ではキャッシュを使用せず、依存関係がうまく解決できない、ということが発生しうるからです。
レイヤーについては以下の記事が参考になります。
以下のように変更します。
FROM ubuntu:20.04
RUN apt-get update && apt-get -y install curl
ENV URL https://google.com/this-will-fail?secret-token=
CMD ["sh", "-c", "curl --head $URL=2e064aad-3a90-4cde-ad86-16fad1f8943e"]
続いて3番の「Remove the hardcoded secret value 2e064aad-3a90–4cde-ad86–16fad1f8943e
. The secret value should be passed into the container during runtime as env variable TOKEN
」
こちらはシークレットをコンテナに持たせず、コンテナを立ち上げるときに環境変数として渡せ、と言っています。
Dockerfileに直接シークレットを含めると、イメージを共有する際やリポジトリにプッシュする際にシークレットが漏洩してしまうリスクがあります。環境変数として実行時に渡すことで、このリスクを軽減できます。
また、同じイメージを使用して異なるシークレット値を簡単に渡すことができるため、異なる環境(例えば、開発環境、本番環境)で同じイメージを使う場合に便利です。
FROM ubuntu:20.04
RUN apt-get update && apt-get -y install curl
ENV URL https://google.com/this-will-fail?secret-token=
CMD ["sh", "-c", "curl --head $URL$TOKEN"]
実行時は以下のようにして環境変数を渡します。
podman build -t app .
podman run -e TOKEN=2e064aad-3a90-4cde-ad86-16fad1f8943e app
最後に4番「Make it impossible to podman exec
, docker exec
or kubectl exec
into the container using bash
」
これはbashを使ってコンテナに入れないようにしなさい、と言っています。
以下のようにすればよいです。
FROM ubuntu:20.04
RUN apt-get update && apt-get -y install curl
ENV URL https://google.com/this-will-fail?secret-token=
RUN rm /usr/bin/bash
CMD ["sh", "-c", "curl --head $URL$TOKEN"]
このようにファイルを削除してからビルドする、という方法もありますが、そもそもベースイメージに無駄なファイルが存在しない軽量のものを使用する、という手もあります。