2021の12月も、後半。1年があっという間。週末六本木ヒルズを通ったら、すごい人出であった。
この2年、コロナの収束とはいかず、
コロナの名が、Covid-19→デルタ→オミクロンと、徐々にとマーベル・コミックのヴィラン名の番付けのように凶暴化しているのが気になる今日このごろ。この先、ずっとワクチンを打ち続けなければならないのか?という疑問もある。
感染予防対策とセキュリティ対策の共通なのは、一人一人の基本的な対策なしには成り立たないという部分があげられ。
どこまでやればいいかという部分が悩ましいところですよね。
今日は、
デベロッパなら避けてとおれないDockerのセキュリティについて、SnykのBlogからお届けしたいと思います。
###序章
https://snyk.io/blog/10-docker-image-security-best-practices/
クラウドネイティブセキュリティ | DEVSECOPS | オープンソース
Dockerのセキュリティにおける10のベストプラクティス
Liran Tal(リラン・タル)、Omer Levi Hevroni(オマー リーバイ ヘヴロ二)
2019年3月6日
Dockerコンテナのセキュリティ
Dockerコンテナのセキュリティのトピックにおいては、Dockerfileのセキュリティ(Dockerベースイメージと潜在的なセキュリティの設定ミスに関連するもの)から、ネットワークポート、ユーザー権限、Dockerにマウントされたファイルシステムアクセスなどに関連する実行時のDockerコンテナのセキュリティに至るまで、さまざまな懸念が提起されています。
この記事では、(1) Dockerイメージの構築に関連するDockerコンテナーのセキュリティの側面、(2) Dockerベースイメージによって導入されるセキュリティの脆弱性の数の削減、(3) Dockerfileのセキュリティのベストプラクティスに焦点を当て紹介します。
Dockerセキュリティとは何ですか?
Dockerセキュリティとは、Dockerコンテナのビルド、ランタイム、およびオーケストレーションの側面のことを指します。これには、DockerベースイメージのDockerfileセキュリティの側面と、Dockerコンテナのセキュリティランタイムの側面(ユーザー権限、Dockerデーモン、コンテナの適切なCPU制御、さらに大規模なDockerコンテナのオーケストレーションに関する懸念など)が含まれます。
Dockerコンテナのセキュリティの状態は、次の4つの主要なDockerセキュリティの問題を明らかにします。
- Dockerfileのセキュリティとベストプラクティス
- ランタイムにおけるDockerコンテナのセキュリティ
- Docker Hubによるサプライチェーンのセキュリティリスクと、それらがDockerコンテナイメージに与える影響
- KubernetesとHelmに関連するクラウドネイティブコンテナオーケストレーションのセキュリティの側面
今回のチートシートでは、Dockerのセキュリティに焦点を当て、Dockerのセキュリティのベストプラクティスと、より安全で高品質なDockerイメージを保証するガイドラインについて説明します。
「Dockerセキュリティレポート:Dockerセキュリティをシフトレフトする」もご覧ください
##Dockerのセキュリティにおける10ベストプラクティス
###1. ベースイメージを最小化する
一般的なDockerコンテナのセキュリティ問題として、Dockerコンテナのイメージが大きくなることが挙げられます。多くの場合、プロジェクト開始の際に「デフォルト」にて、FROM node
でDockerfile
を書き込むなど、一般的なDockerコンテナイメージを使用しているかもしれません。ここで注意しなければならないことは、ノードイメージを指定した際に、完全にインストールされたDebian Stretchディストリビューションが、ノードイメージの構築に使用されるベースとなるイメージであることです。プロジェクトに一般的なシステムライブラリやシステムユーティリティが必要ない場合は、完全フルバージョンのオペレーティングシステム(OS)をベースイメージとして使用しないことを推奨します。
Snykのオープンソースセキュリティレポート2020についてでは、Docker Hub Webサイトで紹介されている人気のあるDockerコンテナの多くが、多くの既知の脆弱性を含むバンドルイメージであることがわかりました。たとえば、docker pull node
などの一般的にダウンロードされているノードイメージを使用した場合、システムライブラリに642の既知の脆弱性がある完全フルバージョンのオペレーティングシステムをあなたのアプリケーションのために導入したことになります。この方法では、最初から不要なDockerセキュリティの問題を追加で背負うことになります。
最も人気のあるDockerイメージのトップ10には、それぞれ少なくとも30の脆弱性が含まれていま。
ご覧のとおり、オープンソースセキュリティレポート2020によると、Ubuntuを除き、Docker Hubで検査した上位10個のDockerイメージに既知の脆弱性が含まれていました。プロジェクトの実行に必要なシステムツールとライブラリのみをバンドルする最小限のイメージを使うことを優先することで、攻撃者の攻撃対象領域を最小限に抑え、安全なOSを確実に準備することが可能です。
Dockerイメージの保護の詳細
###2.最小特権ユーザー
Dockerfile
がUSER
を指定しない場合、コンテナはデフォルトでrootユーザーを使用して実行されます。実際には、コンテナにroot権限が必要な理由はほとんどなく、Dockerのセキュリティ問題となる可能性があります。なぜかというと、Dockerは、デフォルトでrootユーザーを使用してコンテナを実行するため、その名前空間が実行中のコンテナのrootユーザーにマップされると、コンテナがDockerホストへのrootアクセス権を持つ可能性があることを意味するためです。コンテナ上のアプリケーションをrootユーザーで実行すると、攻撃対象領域がさらに広がり、加えてアプリケーション自体が搾取に対して脆弱な場合、特権昇格への容易なパスも与えてしまいます。
露出を最小限に抑えるために、オプトインして、アプリケーションのDockerイメージに専用ユーザーと専用グループを作成しましょう。Dockerfile
のUSER
ディレクティブを使用して、コンテナが可能な限り最小の特権アクセスでアプリケーションを実行するようにします。
特定のユーザーがイメージ内に存在しない可能性がある場合、Dockerfile
の手順を使用してそのユーザーを作成します。
以下に一般的なUbuntuイメージに対して上記を行う方法を例示します。
FROM ubuntu RUN mkdir /app RUN groupadd -r lirantal && useradd -r -s /bin/false -g lirantal lirantal WORKDIR /app COPY . /app RUN chown -R lirantal:lirantal /app USER lirantal CMD node index.js
上記の例:
- パスワード、ホームディレクトリの設定、シェルのないシステムユーザー(-r)を作成します。
- 作成したユーザーを、事前に作成した既存のグループに追加します。(groupaddを使用)
- 作成したグループに関連付けて、作成するユーザー名に最後の引数セットを追加します。
Node.js と alpine イメージには、node
と呼ばれる一般的なユーザーがバンドルされています。これは、汎用ノードユーザーを利用したNode.jsの例です。
FROM node:10-alpine RUN mkdir /app COPY . /app RUN chown -R node:node /app USER node CMD [“node”, “index.js”]
Node.jsアプリケーションを開発している場合は、公式のDockerおよびNode.jsのベストプラクティスを参照することを推奨します。
###3. イメージの検証と署名によりMITM攻撃を軽減する
Dockerイメージの真正性 (authenticity)を確保するというのは難しい課題です。これらのイメージは、本番環境でコードを実行するコンテナとして使用されているため、高い信頼性が要求されます。このため、私たちがプルするイメージが発行者によってプッシュされたものであり、誰もそれを変更していないことを確認することが重要です。改ざんは、ネットワークを介して、Dockerクライアントとレジストリ間で、または悪意のあるイメージをプッシュするために所有者のアカウントのレジストリを侵害することによって発生する可能性があります。
Dockerイメージを確認する
Dockerのデフォルトでは、真正性を検証せずにDockerイメージをプルできます。そのため、発信元と作成者が検証されていない恣意的なDockerイメージが提示される可能性があります。
ポリシーに関係なく、イメージを取り込む前に常にイメージを確認することをベストプラクティスとしましょう。検証を確認するには、次のコマンドを使用してDocker ContentTrustを一時的に有効にします。
export DOCKER_CONTENT_TRUST=1
試しに署名されていないことがわかっているイメージをプルしようとします。要求は拒否され、イメージはプルされません。
####Dockerイメージに署名する
出所と信頼性を検証できないイメージよりも、DockerHubによって精査およびキュレートされた信頼できるパートナーからの Docker 認定 を優先しましょう。
Dockerにてイメージに署名できるため、追加の保護レイヤーが提供されます。イメージに署名するには、Docker Notary を使用します。Notaryはイメージの署名を確認し、イメージの署名が無効な場合はイメージの実行をブロックします。
上記のように、Docker Content Trustが有効になっている場合、Dockerイメージビルドがイメージに署名します。イメージが初めて署名されると、Dockerはユーザーの秘密鍵を生成して~/docker/trust
に保存します。この秘密鍵は、作成時に追加のイメージに署名するために使用されます。
署名付イメージの設定の詳細な手順については、Dockerの公式ドキュメントを参照してください。
ところで、Docker の Content Trust と Notary を使用して Docker イメージに署名することは、GPGを使用する事とはどのように異なるのでしょうか?DiogoMónicaはこの事について素晴らしい話をしています。彼の話によると、本質的にGPGは、リプレイ攻撃ではなく、検証に役立ちます。
###4.オープンソースの脆弱性を検知、修正、監視する
Dockerコンテナのベースイメージを選択するとき、ベースイメージにバンドルされているすべてのコンテナセキュリティの懸念のリスクを間接的に負うことになります。例えば、オペレーティングシステムのセキュリティに問題のある不適切に構成されたデフォルト設定や選択したベースイメージにバンドルされているシステムライブラリなどです。
これらに対処する最初のステップは、問題なくアプリケーションを実行できるようにしながらも、可能な限り最小限にしたベースイメージを利用することです。これは、脆弱性への露出を制限することにより、攻撃対象領域を減らすのに役立ちます。一方、それ自体で監査を実行することはなく、使用しているベースイメージのバージョンで開示される可能性のある将来の脆弱性からユーザーを保護することもできません。
このため、オープンソースセキュリティソフトウェアの脆弱性から保護する1つの方法は、Snykなどのツールを使用して、使用中のすべてのDockerイメージレイヤーに存在する可能性のある脆弱性の継続的なDockerセキュリティスキャンと監視を追加することです。
次のコマンドを使用して、Dockerイメージをスキャンして既知の脆弱性を探します。
`# fetch the image to be tested so it exists locally
$ docker pull node:10
scan the image with snyk
$ snyk test --docker node:10 --file=path/to/Dockerfile`
既知の脆弱性についてDockerイメージを監視し、イメージ内で新たに発見された脆弱性が見つかると、Snykが通知して修正アドバイスを提供できるようにします。
$ snyk monitor --docker node:10
Snykユーザーが実行したスキャンに基づいて、Dockerイメージスキャンの44%に既知の脆弱性があり、より新しく、より安全なベースイメージが利用可能であることがわかりました。この修復アドバイスはSnykに固有のものであり、デベロッパはこれに基づいてアクションを実行し、Dockerイメージをアップグレードできます。
またSnykは、すべてのDockerイメージスキャンの20%において、Dockerイメージの再構築のみで「脆弱性の数を減らす」ことができることを発見しました。
####Dockerコンテナのセキュリティを監査する方法は?
Linuxベースのコンテナプロジェクトをスキャンして既知の脆弱性を探し、環境のセキュリティを確保することは重要なタスクです。Snykはこのタスクを実現するために、ベースイメージ内の:パッケージマネージャーと主要なバイナリ(パッケージマネージャーを介してインストールされなかったレイヤー)によってインストールおよび管理されるオペレーティングシステム(OS)パッケージなどの
依存関係をスキャンします。
コンテナセキュリティ用の無料ツールであるSnykを是非使用してください。スキャン結果に基づいて、Snykは、ベースイメージの推奨事項、脆弱性が見つかったDockerfileレイヤーなどを示すことで、パブリックDockerHubイメージの修復アドバイスとガイダンスを提供します。
###5.Dockerイメージに機密情報を漏洩しない
Dockerイメージ内でアプリケーションを構築する場合、プライベートリポジトリからコードをプルするためのSSH秘密鍵などのシークレットやプライベートパッケージをインストールするためのトークンが必要な場合があります。それらをDocker中間コンテナにコピーすると、後で削除したとしても、追加されたレイヤーにキャッシュされます。これらのトークンとキーは、Dockerfile
の外部に保持する必要があります。
####マルチステージビルドの使用
Dockerコンテナのセキュリティを向上させるもう1つの側面は、マルチステージビルドを使用することです。マルチステージビルドのDockerサポートを活用することで、機密データがイメージビルドに到達しないように、後で破棄される中間イメージレイヤーでシークレットをフェッチして管理します。次の例のように、コードを使用して、上記の中間層にシークレットを追加します。
FROM ubuntu as intermediate
WORKDIR /app COPY secret/key /tmp/ RUN scp -i /tmp/key build@acme/files .
FROM ubuntu WORKDIR /app COPY --from=intermediate /app .
####Docker secret コマンドの使用
次のように、Dockerのアルファ機能を使用してシークレットを管理し、機密ファイルをキャッシュせずにマウントします。
# syntax = docker/dockerfile:1.0-experimental FROM alpine
# shows secret from default secret location RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecre
# shows secret from custom secret location RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar
Docker secretについてはDockerのサイトで詳細を参照してください。
####再帰コピーに注意
ビルド中のイメージにファイルをコピーするときにも注意が必要です。たとえば、次のコマンドはDockerイメージにビルドコンテキストフォルダー全体を再帰的にコピーします。これにより、機密ファイルもコピーされてしまう可能性があります。
COPY . .
フォルダに機密ファイルがある場合は、それらを削除するか、もしくは
.dockerignore
を使用して無視します。
private.key appsettings.json
####Dockerコンテナをどのように保護しますか?
マルチステートビルドを使用して、本番用にビルドされたコンテナイメージに、開発アセットやシークレット、トークンがないことを確認してください。
さらに、無料で使用できるSnykなどのコンテナセキュリティツールを使用して、CLIやDocker Hubから直接、またはAmazon ECR、GoogleGCRなどを使用して本番環境にデプロイされたDockerイメージをスキャンしていることを確認してください。
###6.不変性のために固定タグを使用する
各Dockerイメージは、同じイメージのバリアントである複数のタグを持つことができます。最も一般的なタグはlatestで、これはイメージの最新バージョンを表します。イメージタグは不変ではなく、イメージの作成者は同じタグを複数回公開できます。
一方でこれは、Dockerファイルのベースイメージがビルド間で変更される可能性があることを意味します。これにより、ベースイメージに変更が加えられたため、動作に一貫性がなくなる可能性があります。この問題を軽減し、Dockerのセキュリティ状況を改善する方法は複数あります。
-
利用可能な最も具体的なタグを優先します。イメージに:8と:8.0.1さらには:8.0.1-alpineなどの複数のタグがある場合は、後者が最も具体的なイメージ参照であるため、後者を優先します。最新などのよくある一般的なタグの使用は避けてください。特定のタグを固定すると、最終的に削除される可能性があることに注意してください。
-
特定のイメージタグが使用できなくなり、それに依存するチームにて問題となる場合、自分の管理下にあるレジストリまたはアカウントでこのイメージのローカルミラーを実行することを検討してください。なお、このアプローチにて必要なメンテナンスのオーバーヘッドを考慮することが重要です。なぜなら、レジストリをメンテナンスする必要があることを意味するためです。使用するイメージを自分が所有するレジストリに複製することは、使用するイメージが変更されないようにするための良い方法です。
-できるだけ具体的にしましょう。タグをプルする代わりに、Dockerイメージの特定のSHA256参照を使用してイメージをプルします。これにより、プルするたびに同じイメージが取得されることが保証されます。ただし、イメージが変更された場合、そのハッシュが存在しなくなる可能性があるため、SHA256参照を使用するとリスクが生じる可能性があることに注意してください。
####Dockerイメージは安全ですか?
Dockerイメージは、オープンソースのLinuxディストリビューションに基づいており、オープンソースのソフトウェアとライブラリをバンドルしている場合があります。Snykが実施した最近のオープンソースセキュリティ調査では、最も人気のあるdocker イメージに少なくとも30の脆弱性が含まれている ことがわかっています。
###7.ADDの代わりにCOPYを使用します
Docker にはホストからファイルをコピーしてDocker イメージを構築するための2つのコマンド ( COPY
および ADD
)が用意されています。手順は本質的には似ていますが、機能が異なるため、場合によってイメージにおけるDockerコンテナのセキュリティの問題が発生する可能性があります。
- COPY —明示的なソースおよび宛先ファイルまたはディレクトリを指定して、ローカルファイルを再帰的にコピーします。COPYでは、場所を宣言する必要があります。
- ADD —ローカルファイルを再帰的にコピーし、宛先ディレクトリが存在しない場合は暗黙的に作成し、アーカイブをローカルURLまたはリモートURLとしてソースとして受け入れ、それぞれ宛先ディレクトリに展開またはダウンロードします。
とても微妙ですが、ADDとCOPYの違いは重要です。潜在的なセキュリティ問題を回避するために、この2つのコマンドの違いに注意してください。
- リモートURLを使用してデータをソースの場所に直接ダウンロードすると、ダウンロードされるファイルのコンテンツを変更する中間者攻撃が発生する可能性があります。加えてリモートURLの発信元と信頼性をさらに検証する必要があります。COPYを使用する場合、リモートURLからダウンロードするファイルのソースは、安全なTLS接続を介して宣言する必要があり、それらの発信元も検証する必要があります。
- スペースとイメージレイヤーの考慮事項:COPYを使用すると、アーカイブの追加をリモートロケーションから分離し、異なるレイヤーとしてアンパックできます。これにより、イメージキャッシュが最適化されます。リモートファイルが必要な場合は、それらすべてを1つのRUNコマンドに結合して、後でダウンロード、抽出、およびクリーンアップすることで、ADDが使用された場合に必要となる複数のレイヤーにわたる単一レイヤー操作を最適化することが可能です。
- ローカルアーカイブが使用されている場合、ADDはそれらを宛先ディレクトリに自動的に解凍します。これは許容できるかもしれませんが、自動的にトリガーされる可能性のあるzip爆弾とZipSlipの脆弱性のリスクが追加されます。
###8.メタデータラベルを使用する
イメージラベルは、作成しているイメージのメタデータを提供します。これにより、ユーザーはイメージの使い方を簡単に理解できます。最も一般的なラベルは「maintainer」です。これは、このイメージを管理している人の電子メールアドレスと名前を指定します。次のLABEL
コマンドでメタデータを追加します。
LABEL maintainer="me@acme.com"
maintainerの連絡先に加えて、重要なメタデータを追加します。このメタデータには、コミットハッシュ、関連するビルドへのリンク、品質ステータス(すべてのテストに合格しましたか?)、ソースコード、SECURITY.TXT ファイルの場所への参照などが含まれます。
以下のようなラベルを追加するときは、Dockerラベルスキーマの責任ある開示ポリシーを指すSECURITY.TXT(RFC5785)ファイルを採用することを推奨します。
LABEL securitytxt="https://www.example.com/.well-known/security.txt"
Dockerイメージのラベルの詳細については、https://label-schema.org/rc1/を参照してください。
###9.小さくて安全なDockerイメージにマルチステージビルドを使用する
Dockerfile
を使用してアプリケーションをビルドすると、ビルド時にのみ必要な多くのアーティファクトが作成されます。これらは、コンパイルに必要な開発ツールやライブラリなどのパッケージ、または単体テスト、一時ファイル、シークレットなどの実行に必要な依存関係、等々です。
これらのアーティファクトを本番環境で使用される可能性のあるベースイメージに保持すると、Dockerイメージのサイズが大きくなり、ダウンロードにかかる時間に悪影響を与えるだけでなく、結果としてインストールされるパッケージが増えるため、攻撃対象領域が増える可能性があります。使用しているDockerイメージについても同じことが言えます。ビルドには特定のDockerイメージが必要になる場合がありますが、アプリケーションのコードを実行するためには必要ありません。
Golangが良い例です。Golangアプリケーションをビルドするには、Goコンパイラが必要です。コンパイラは、スクラッチイメージを含む依存関係なしで、任意のオペレーティングシステムで実行される実行可能ファイルを生成します。
これが、Dockerにマルチステージビルド機能がある理由です。この機能を使用すると、ビルドプロセスで複数の一時イメージを使用して、コピーした情報とともに最新のイメージのみを保持できます。このようにすることで、2つのイメージを持つことができます。
- 最初のイメージ:非常に大きなイメージサイズで、アプリのビルドとテストの実行に使用される多くの依存関係がバンドルされています。
- 2番目のイメージ:ライブラリのサイズと数の点で非常に小さいイメージであり、本番環境でアプリを実行するために必要なアーティファクトのコピーのみが含まれています。
###10. linter を使用する
linter の使用を取り入れ、よくある間違いを回避し、エンジニアが自動化された方法に従うことができるベストプラクティスのガイドラインを確立します。これはDockerfileのセキュリティ問題を静的に分するために有益なDocker セキュリティのスキャンタスクとなります。
そのような linter の1つがhadolintです。Dockerfileを解析し、ベストプラクティスのルールに一致しないエラーがある場合は警告を表示します。
Hadolintは、統合開発環境(IDE)内で使用すると、さらに強力になります。たとえば、hadolintをVSCode拡張機能として使用すると、入力中にリンティングエラーが表示されるので、より優れたDockerfileをより迅速に作成するのに役立ちます。
####Dockerコンテナイメージをどのように強化しますか?
Dockerfileの構成が安全であることを確認するために、hadolintやdockleなどのIinterを使用できます。コンテナイメージもスキャンして、本番コンテナのセキュリティに深刻な影響を与える脆弱性を回避してください。安全なイメージを確保するために、Dockerイメージセキュリティのベストプラクティス10を読むことを推奨します。
####Dockerはセキュリティリスクがありますか?
Dockerは、人気のある、広く採用されたソフトウェア仮想化のテクノロジーです。Dockerをビルドしてデプロイするときは、Dockerベースイメージにバンドルされているセキュリティの脆弱性や、Dockerコンテナの設定ミスによるデータ侵害などの懸念を軽減するために、セキュリティのベストプラクティスを念頭に置いて行う必要があります。
####Dockerコンテナを保護するにはどうすればよいですか?
Dockerセキュリティのベストプラクティスに従って、既知の脆弱性がほとんどまたはまったくないDockerベースイメージ、Dockerfileセキュリティ設定を使用していることを確認し、デプロイされたコンテナを監視して、開発と本番の間にイメージのずれがないことを確認します。さらに、コンテナオーケストレーションのソリューションが 以下の Infrastructure as Codeのベストプラクティスに従っていることを確認してください。
最後に、Node.jsおよびJavaアプリケーションに最適なDockerイメージを構築するための追加のセキュリティのベストプラクティスを以下に紹介します。
1.あなたはJava開発者ですか?
Java開発者向けのDocker:セキュリティを失敗させないために知っておくべき5つのこと原文
-
Dockerを使用してJavaコンテナを構築するための10のベストプラクティス
Javaアプリケーション用の本番グレードのコンテナを構築する方法に関する詳細なガイド -
Dockerを使用してNode.js Webアプリケーションをコンテナー化するための10のベストプラクティス
Node.js開発者向けに、Node.jsアプリケーション用にパフォーマンスの高い安全なDockerベースイメージを構築する方法をステップバイステップのウォークスルーで説明しています
--
長い翻訳文でしたが、最後まで読んでいただいてありがとうございました!!
Contents provided by:
Jesse Casman, Fumiko Doi, Content Strategists for Snyk, Japan, and Randell Degges, Community Manager for Snyk Global