DockerFileセキュリティベストプラクティス
7664 ワード
コンテナのセキュリティは広い問題スペースであり、リスクを軽減するために収穫することができる多くの低い絞首刑の果物があります.良い出発点は、dockerfileを書くとき、何らかの規則に従うことです.
私は一般的なセキュリティ問題のリストをコンパイルしてどのようにそれらを避けるために.すべての問題についても私はOpen Policy Agent ( OPA )ルールを使用してDockerFilesを静的に解析しますconftest . これ以上の左シフトすることはできません!
あなたは
環境変数に秘密を保管しないでください
秘密の配布は毛深い問題であり、それは間違ってそれを行うのは簡単です.コンテナ化されたアプリケーションについては、ボリュームをマウントすることによってファイルシステムからそれらを表面化することができます.
使用
検出方法
信頼できるベースイメージのみを使用する
コンテナ化されたアプリケーションのためのサプライチェーン攻撃も、コンテナ自体を構築するのに用いられる層の階層から来ます.
主な犯人は明らかにベースイメージが使用されます.信頼されていないベースの画像は高いリスクであり、可能な限り避けてください.
Dockerは、Aを提供しますset of official base images ほとんどのオペレーティングシステムやアプリケーションを使用します.それらを使用することによって、私たちはいくつかの種類の共有責任をレッカー自身とレバレッジすることによって妥協のリスクを最小にします.
検出方法
信頼の定義は文脈によって異なります.
ベースイメージの'最新'タグを使用しないでください
あなたのベースイメージのバージョンをピン止めすることは、あなたが構築しているコンテナの予測可能性に関してあなたに心の若干の平和を与えます.
あなたが最新に頼るならば、あなたは黙って最高の最悪のケースであなたのアプリケーション信頼性に影響を及ぼすかもしれない更新パッケージを継承するかもしれません.
検出方法
避けてカールカール
インターネットからものを引いて、それをシェルに配管することは、それがそうでありえるのと同じくらい悪いです.残念ながら、ソフトウェアのインストールを合理化する広範囲の解決策です.
信頼できるソースを使用する セキュア接続を使用する あなたがダウンロードするものの真正性と完全性を確かめる 検出方法
システムパッケージをアップグレードしないでください
これは少しのストレッチかもしれませんが、推論は以下の通りです:あなたがそうするならば、あなたはあなたのソフトウェア依存のバージョンをピンでとめたいです
アップグレードを行う場合は、使用している
あなたがしたいことは、ベースイメージのバージョンをピンするだけです
検出方法
可能ならばアドインを使わない
つの小さな特徴
セキュリティの観点から、同じアドバイスが適用されます:ない.前に必要なコンテンツを取得し、それを確認してから
注意:動的にビルドしたシステムで、dockerfileを動的に生成します.
検出方法
根を出さない
コンテナのルートは、ホストマシンと同じルートですが、Dockerデーモンの設定によって制限されます.たとえ制限があっても、俳優が容器から抜け出せば、ホストへのフルアクセスを得る方法を見つけることができるでしょう.
もちろん、これは理想的ではありません、そして、あなたの脅威モデルはルートとして走ることによってもたらされる危険を無視することができません.
このように常にユーザを指定するのがベストです.
代わりに、深さのアプローチで防御を採用し、スタック全体をさらに軽減します.厳密にはDockerデーモンを設定するか、ルートレスコンテナソリューションを使用して、ランタイム設定を制限します
検出方法
しないでください
として
ユーザーとして実行しても、ユーザーが
謝辞
この作品は、触発されているとの繰り返しですprior art からMadhu Akula .
この投稿は面白かったですか.あなたの考えを聞きたいです.
私は一般的なセキュリティ問題のリストをコンパイルしてどのようにそれらを避けるために.すべての問題についても私はOpen Policy Agent ( OPA )ルールを使用してDockerFilesを静的に解析しますconftest . これ以上の左シフトすることはできません!
あなたは
.rego
ルールセットthis repository . フィードバックと貢献に感謝します.環境変数に秘密を保管しないでください
秘密の配布は毛深い問題であり、それは間違ってそれを行うのは簡単です.コンテナ化されたアプリケーションについては、ボリュームをマウントすることによってファイルシステムからそれらを表面化することができます.
使用
ENV
DockerFileが通常アプリケーションで配布されるので、秘密を保存することは悪い習慣です.したがって、コードでハードコーディング秘密からの違いがありません.検出方法
secrets_env = [
"passwd",
"password",
"pass",
# "pwd", can't use this one
"secret",
"key",
"access",
"api_key",
"apikey",
"token",
"tkn"
]
deny[msg] {
input[i].Cmd == "env"
val := input[i].Value
contains(lower(val[_]), secrets_env[_])
msg = sprintf("Line %d: Potential secret in ENV key found: %s", [i, val])
}
信頼できるベースイメージのみを使用する
コンテナ化されたアプリケーションのためのサプライチェーン攻撃も、コンテナ自体を構築するのに用いられる層の階層から来ます.
主な犯人は明らかにベースイメージが使用されます.信頼されていないベースの画像は高いリスクであり、可能な限り避けてください.
Dockerは、Aを提供しますset of official base images ほとんどのオペレーティングシステムやアプリケーションを使用します.それらを使用することによって、私たちはいくつかの種類の共有責任をレッカー自身とレバレッジすることによって妥協のリスクを最小にします.
検出方法
deny[msg] {
input[i].Cmd == "from"
val := split(input[i].Value[0], "/")
count(val) > 1
msg = sprintf("Line %d: use a trusted base image", [i])
}
この規則はDockerHookの公式イメージに向けられている.私が名前空間の不在を見つけるだけであるので、それは非常にダムです.信頼の定義は文脈によって異なります.
ベースイメージの'最新'タグを使用しないでください
あなたのベースイメージのバージョンをピン止めすることは、あなたが構築しているコンテナの予測可能性に関してあなたに心の若干の平和を与えます.
あなたが最新に頼るならば、あなたは黙って最高の最悪のケースであなたのアプリケーション信頼性に影響を及ぼすかもしれない更新パッケージを継承するかもしれません.
検出方法
deny[msg] {
input[i].Cmd == "from"
val := split(input[i].Value[0], ":")
contains(lower(val[1]), "latest"])
msg = sprintf("Line %d: do not use 'latest' tag for base images", [i])
}
避けてカールカール
インターネットからものを引いて、それをシェルに配管することは、それがそうでありえるのと同じくらい悪いです.残念ながら、ソフトウェアのインストールを合理化する広範囲の解決策です.
wget https://cloudberry.engineering/absolutely-trustworthy.sh | sh
リスクはサプライチェーン攻撃のために同じ枠組みであり、それは信頼を沸騰させる.もし本当にbashをカールさせなければならないなら、deny[msg] {
input[i].Cmd == "run"
val := concat(" ", input[i].Value)
matches := regex.find_n("(curl|wget)[^|^>]*[|>]", lower(val), -1)
count(matches) > 0
msg = sprintf("Line %d: Avoid curl bashing", [i])
}
システムパッケージをアップグレードしないでください
これは少しのストレッチかもしれませんが、推論は以下の通りです:あなたがそうするならば、あなたはあなたのソフトウェア依存のバージョンをピンでとめたいです
apt-get upgrade
あなたが効果的にすべての最新バージョンにアップグレードされます.アップグレードを行う場合は、使用している
latest
ベースイメージのタグは、依存関係ツリーの予測不可能性を増幅します.あなたがしたいことは、ベースイメージのバージョンをピンするだけです
apt/apk update
.検出方法
upgrade_commands = [
"apk upgrade",
"apt-get upgrade",
"dist-upgrade",
]
deny[msg] {
input[i].Cmd == "run"
val := concat(" ", input[i].Value)
contains(val, upgrade_commands[_])
msg = sprintf(“Line: %d: Do not upgrade your system packages", [i])
}
可能ならばアドインを使わない
つの小さな特徴
ADD
コマンドは、リモートURLを指すことができ、ビルド時にコンテンツを取得できます.ADD https://cloudberry.engineering/absolutely-trust-me.tar.gz
皮肉なことに、公式ドキュメントは代わりにカールバッシングを使用することを提案します.セキュリティの観点から、同じアドバイスが適用されます:ない.前に必要なコンテンツを取得し、それを確認してから
COPY
. しかし、あなたが本当に持っているならば、安全な接続の上に信頼された源を使用してください.注意:動的にビルドしたシステムで、dockerfileを動的に生成します.
ADD
効果的にシンクを求めている.検出方法
deny[msg] {
input[i].Cmd == "add"
msg = sprintf("Line %d: Use COPY instead of ADD", [i])
}
根を出さない
コンテナのルートは、ホストマシンと同じルートですが、Dockerデーモンの設定によって制限されます.たとえ制限があっても、俳優が容器から抜け出せば、ホストへのフルアクセスを得る方法を見つけることができるでしょう.
もちろん、これは理想的ではありません、そして、あなたの脅威モデルはルートとして走ることによってもたらされる危険を無視することができません.
このように常にユーザを指定するのがベストです.
USER hopefullynotroot
dockerfileにユーザを明示的に設定することは防御の1つの層であり、全体を解決しないことに注意してくださいrunning as root problem .代わりに、深さのアプローチで防御を採用し、スタック全体をさらに軽減します.厳密にはDockerデーモンを設定するか、ルートレスコンテナソリューションを使用して、ランタイム設定を制限します
--privileged
可能ならば等)など.検出方法
any_user {
input[i].Cmd == "user"
}
deny[msg] {
not any_user
msg = "Do not run as root, use USER instead"
}
しないでください
として
do not root
, あなたはいずれもsudoしない.ユーザーとして実行しても、ユーザーが
sudoers
クラブ.deny[msg] {
input[i].Cmd == "run"
val := concat(" ", input[i].Value)
contains(lower(val), "sudo")
msg = sprintf("Line %d: Do not use 'sudo' command", [i])
}
謝辞
この作品は、触発されているとの繰り返しですprior art からMadhu Akula .
この投稿は面白かったですか.あなたの考えを聞きたいです.
hello AT cloudberry.engineering
クラウドセキュリティについて書きましたblog , を購読することができますRSS feed またはnewsletter .Reference
この問題について(DockerFileセキュリティベストプラクティス), 我々は、より多くの情報をここで見つけました https://dev.to/gbrindisi/dockerfile-security-best-practices-13n9テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol