10 Docker Image Security Best PracticesーPart 2

Dockerイメージセキュリティのベストプラクティス 10のコツー第2章

gavin.zhou
8 min readJan 7, 2020

前回の続きです。残りの5つのコツを見ていきたいと思います。

6. Use fixed tags for immutability

それぞれのDockerイメージはたくさんのタグがついていることがあります。そのタグは、同じイメージのバリアントです。一番一般的なタグは、 latestで、最新バージョンのイメージを意味します。イメージタグは変更できません。そして、イメージの作成者であれば、同じタグを何回も発行することができます。

これはつまり、Dockerファイルに対するベースイメージがビルド間で変化する可能性を示唆しています。ベースイメージへの変更が原因で、非継続てきなビヘイビアになるのです。この問題を緩和する方法をいくつかご紹介します。

・一番明確で有効なタグを優先する事。もしそのイメージに:8 、8.0.1 や、8.0.1-alpineなど多くのタグがついているのであれば、一番最後のものを優先してください。というのも、一番明確な参照されるイメージだからです。「latest」のような最も一般的なタグを使うのは避けてください。特定のタグをピンする時に、削除されてしまうことがあるということも頭に入れておいてください。

・特定のイメージタグが利用不可能になったり、致命的な問題の引き金になったりする問題を軽減するため、このレジストリの中のローカルミラーを走らせること、もしくは自分のコントロールできるようにしておくことが必要です。この方法にはメンテナンス費用が必要になってくるということを考慮するようにしてください。というのも、この方法ではレジストリを維持する必要があるからです。自分の持っているレジストリの中で必要なイメージを複製するのは、使用するイメージが変更されない確実な方法なので、良い方法だと思います。

・ものすごく分かりやすくすること!タグをプルする代わりに、Dockerイメージの特定のSHA256を使ってイメージをプルします。そうすると毎回のプルで同じイメージが取得できることを保証してくれます。しかし、そのイメージがもう存在しないハッシュを変更する場合は、SHA256を使うのは少しリスキーです。

7. Use COPY instead of ADD

Dockerでは構築の際に、ホストからDockerイメージへコピーをファイルするための2つのコマンドを利用できるようになります。 COPY と ADDです。本質的にインストラクションは似ていますが、機能的には異なります。

  • COPY — 明示的なソースおよび宛先ファイルまたはディレクトリを指定して、ローカルファイルを再帰的にコピーします。COPYではロケーションを申告する必要があります。
  • ADD — これはローカルファイルを再帰的にコピーし、存在しない場合は暗黙的に宛先ディレクトリを作成し、ソースとしてローカルまたはリモートURLとしてアーカイブを受け入れ、それぞれ宛先ディレクトリに展開またはダウンロードします。

ADD とCOPYの違いはとても重要です。潜在的なセキュリティ面の問題を避けるために以下の違いを把握しておいてください。

  • リモートURLを使用してデータをソースの場所に直接ダウンロードすると、ダウンロードされるファイルのコンテンツを変更する中間者攻撃を引き起こす可能性があります。さらに言えば、リモートURLの出どころやオーセンティシティはきちんと検証されるべきです。COPYを使う場合リモートURLからダウンロードされたファイルのソースはセキュアなTLSコネクションを通して申告されるべきです。そして、出どころも検証されるべきです。
  • スペースとイメージレイヤーの考慮事項:COPYを使うことで、アーカイブの追加をリモートロケーションから分離し、異なるレイヤーとして展開することができます。これにより、イメージキャッシュが最適化されます。リモートファイルが必要な場合は、それらすべてを一つのRUNコマンドにまとめて、後でクリーンアップを行い、ADDを使用した場合に必要となる複数のレイヤーでの単一レイヤー操作を最適化します。
  • ローカルアーアイブが使われる場合、ADDは自動的にそれらを宛先ディレクトリに抽出します。これはいいと思いますが、zip爆弾やZip Slip 脆弱性は、自動的に引き金になり危険な状況に陥ります。

8. Use metadata labels

イメージラベルのおかげで、作成中のイメージのメタデータが利用できるようになります。 これにより、ユーザーはイメージの使い方を簡単に理解できます。最も一般的なラベルは、「maintainer」で、これはemailアドレスやこのイメージを保持する人の名前を特定します。以下の LABEL コマンドで、メタデータを追加してください:

LABEL maintainer="me@acme.com"

メンテナーコンタクトに加えて、重要なメタデータは全て追加してください。このメタデータは、コミットハッシュ、関連するビルドへのリンク、クオリティステータス(すべてのテストに合格しましたか?)、ソースコード、SECURITY.TXTファイルの場所などなどを含んでいます。

次のようにラベルを追加する場合、Dockerラベルスキーマに対して信頼度の高い情報開示方針を指すSECURITY.TXT (RFC5785)を導入するのはメリットがあると思います。

LABEL securitytxt="https://www.example.com/.well-known/security.txt"

Dockerイメージのラベルについてもっと詳しい情報がほしい方はこちら https://label-schema.org/rc1/をご一読ください

9. Use multi-stage build for small and secure images

Dockerfileを使ってアプリケーションを構築する間構時のみ必要な、たくさんのアーティファクトが生成されます。これらは、コンパイルに必要な開発ツールやライブラリなどのパッケージ、または単体テスト、一時ファイル、シークレットなどの実行に必要なディペンデンシーです。

プロダクションのために使われるベースイメージの中でそれらのアーティファクトを保持するということは、Dockerイメージのサイズが大きくなることにつながります。そして、より多くのパッケージがインストールされるため、ダウンロードの時間が長くなったり、アタックサーフェス(攻撃領域)が広がったりと悪影響を及ぼします。今使用中のDockerイメージにも同じことが言えます。構築のための特定のDockerイメージが必要になってくるでしょう。しかし、自分のアプリケーションのコードを走らせるためではありません。

Golang はとてもいい例でしょう。Golangアプリケーションを構築するためには、Goコンパイラが必要です。コンパイラは、ディペンデンシーがなく、スクラッチイメージを含む、どのオペレーティングシステム上でも走る実行ファイルを生成します。

Dockerがmulti-stage buildのケーパビリティを持っているということへのいい理由付けになります。この機能で、ビルドプロセスの中で一時的なたくさんのイメージを使うことができ、コピーした情報と共に最新のイメージだけを保持できます。このように、2つのイメージを持つことになります。

  • First image(1番目のイメージ) — とても大きなイメージサイズで、アプリケーションを構築し、テストを実装するために使われている多くのディペンデンシーとバンドルしました。
  • Second image(2番目のイメージ) — とても小さいイメージサイズで、ライブラリの数も少ないものです。実稼働環境でアプリを実行するために必要なアーティファクトのコピーのみが含まれます。

10. Use a linter

linterを使用することで、よくある間違いを避け、自動的な方法でエンジニアが実践しやすいガイドラインを確立することができます。

そのようなlinterとして hadolintがあります。これは、Dockerfileを解析し、そのベストプラクティスルールに合わないエラーを警告してくれます。

Hadolintは、統合開発環境(IDE)の中で使用されるときはより強力なものになります。例えば、VSCodeの拡張機能としてのhadolintを使う場合、lintエラーがタイピング時に現れるので、Dockerfilesをより早く効率的に書くことができます。

docker imagesをもっとセキュアにする方法について学ぶ

表をプリントアウトして、dockerイメージセキュリティのベストプラクティスをどこか目のつくところに貼っておくようにしておくと、dockerイメージを構築する際などに役に立つと思います。

Orangesys.ioでは、kuberneteの運用、DevOps、監視のお手伝いをさせていただいています。ぜひ私たちにおまかせください

--

--

No responses yet