コンテナの特権昇格脆弱性ガイド
コンテナの多くの利点の一つは分離性である。
Linuxのネームスペースとcgroupsを慎重に活用することで、コンテナはプロセスを互いに独立して実行できるサンドボックス環境を構築します。この特性と優れた開発者体験が相まって、コンテナはエンジニアやセキュリティ担当者双方から支持を集めるようになりました。
しかし、それで本当に十分なのか?
そして、万一いずれかが侵害された場合でも、作業負荷が安全であると断言できますか?
さて、今回の記事では、攻撃者にとっての夢でありシステム管理者にとっての悪夢とも言える問題を取り上げ、その発生メカニズムと原因、そしてHacker Newsのトップ記事に載ってしまう前に防ぐ方法を解説します。Dockerコンテナのセキュリティ脆弱性については、こちらをご覧ください:トップ9 Dockerコンテナセキュリティ脆弱性。
コンテナ分離とそのセキュリティ上の脆弱性
コンテナに関して見落とされがちな重要な点は、すべてが同じホストを共有していることです。これは各コンテナのセキュリティレベルが隣り合うコンテナと同等であることを意味します。ホストまたは単一のコンテナが侵害された場合、インフラ全体に壊滅的な影響を及ぼす可能性があります。
これはコンテナを完全に放棄すべきだという意味ではありません。そうではありません。ここで重要なのは、細かい条件を理解することです。
攻撃者が権限昇格の手法を見出すと、隔離は崩れ始める。権限昇格は攻撃的セキュリティ攻撃において最もスリリングでありながら困難な手法の一つだ。低権限の足場をシステム全体の侵害へと変える。
コンテナ特権昇格の脆弱性は、セキュリティ境界の回避をより容易にし、はるかに大きな利益をもたらす。なぜなら、単一のコンテナさえあればホストへのアクセス権を獲得できるからだ。
これは単なる理論ではない。悪名高い 2019年のrunC脆弱性(CVE-2019-5736)により、攻撃者はホストのrunCバイナリを上書きし、ホストのrootアクセス権を奪取することが可能となった。
これらの攻撃は派手さとは程遠い。だからこそ、こんな疑問に直面するかもしれない:

近年では、 CVE-2024-21626のような脆弱性やレイヤーベースの巧妙な攻撃が示すように、Linuxの権限管理機能、マウント、ファイルシステムのレイヤリングを誤用すれば、非rootコンテナであっても危険になり得る。
そのため、前回のDocker脆弱性ガイドを踏まえ、これらの攻撃の手口、リスク増大を示す最近のCVE、そしてその防止策について探っていきます。
最近のコンテナ特権昇格脆弱性
すべてのコンテナ脆弱性が権限昇格につながるわけではないが、最も危険なものは往々にしてそうなる。一部の脆弱性はコンテナの分離を迂回し、他に類を見ないほど高い特権を奪取する。
以下は、最近発見された3つのコンテナ特権昇格脆弱性である。
CVE-2024-21626: runC 作業ディレクトリからの脱出し
CVE-2024-21626は、広く利用されているコンテナランタイムであるrunCに影響を与える、深刻度の高いコンテナ脱出脆弱性です。この脆弱性は、execveとのPR_SET_NO_NEW_PRIVS prctl呼び出しの不安全な使用に起因し、コンテナが過度に許可されたマウントや機能で起動された場合に、攻撃者がno_new_privsフラグをバイパスすることを可能にします。
no_new_privsフラグは、多くのコンテナエンジンがサンドボックス化のために依存する 特権昇格に対する中核的な緩和策の一つである。
この欠陥は、v1.1.11以降のrunCバージョンで導入され、v1.1.12で修正されました。
UbuntuカーネルOverlayFSモジュールにおけるCVE-2023-2640およびCVE-2023-32629
OverlayFSはコンテナとKubernetesの基盤となる構成要素の一つです。単一のLinuxホスト上で2つのディレクトリ(lowerdirとupperdir)をレイヤリングし、それらを単一のディレクトリとして提示します。これにより、docker buildやdocker commitといったレイヤー関連のDockerコマンドのパフォーマンスが向上します。
CVE-2023-2640および CVE-2023-32629 は、悪意のある攻撃者がボリュームマウントを使用した非root特権コンテナを利用して特権を昇格させることを可能にします。 これは、ボリュームマウントが独立したディスクとして扱われ、コンテナレイヤー外に存在するオーバーレイファイルシステム(OverlayFS)の作成に使用できるためです。これにより攻撃者は標準的なコンテナ制限を迂回し、マウントされたボリューム上の拡張ファイル属性を操作できます。これらの属性は、昇格された権限(CAP_SETUID や CAP_SYS_ADMIN など)が保持された状態で上位レイヤーにコピーされます。
CVE-2022-0492
2022年3月4日、 セキュリティ研究者らは Linuxカーネルのcgroup_release_agent_writeに重大な欠陥を発見した。この欠陥により、コンテナからの脱出が可能となり、コンテナが動作するノード全体を制御下に置く恐れがあった。
クラウドプロバイダーとLinuxディストリビューションは迅速に対応した。パッチが発行され、アドバイザリが公開された。しかし、その表面の下では複雑さが残っていた。他のソフトウェアとは異なり、Linuxカーネルにはディストリビューション間で標準化されたバージョン管理方式が存在しない。
つまり、これらのパッチを適用しベースイメージをアップグレードするのに数か月を要した。その間、環境は潜在的な攻撃に対して脆弱な状態が続いた。
Docker および Docker Compose における特権昇格の防止
Dockerコンテナ内部からの特権昇格攻撃を防ぐ最善の方法は、コンテナ内のアプリケーションを非特権ユーザーとして実行するように設定し、コンテナが特権アクセス権を持たないようにすることです。
実際には、Dockerで特権昇格を防ぐには、以下のことを行う必要があります:
- ロック権限の昇格
- 適切な非 root ユーザーを設定する
- Linuxカーネルの機能削除
2つの選択肢があります:実行時か、Docker Compose設定内での設定のいずれかです。
実行時には、以下のフラグを使用してください:
docker run \
--read-only \
--security-opt=no-new-privileges \
--network your-isolated-network \
--cap-drop ALL
--cap-add CHOWN \
--pids-limit 99 \
--user=your-user \ # ルート以外のユーザー名。
... # その他のオプションはここに記述
your-app:v1.0.1Docker Compose を使用する場合、設定は次のようになります:
services:
webapp:
image: your-app:v1.0.1 read_only: true security_opt:
- no-new-privileges:true networks:
- your-isolated-network cap_drop:
- ALL cap_add:
- CHOWN
# その他のオプションはここに記述
...rootユーザーアクセスを必要とするコンテナの実行
コンテナの実行にrootアクセスが必要なケース(システムユーティリティの実行、レガシーサービスなど)があります。このような場合、このユーザーをDockerホスト上の権限の低いユーザーに再マッピングできます。
コンテナのUIDを再マッピングすることで、コンテナが自身をrootとして実行していると認識していても、ホストの観点からは実際には非特権ユーザーとして動作するようになります。これにより、コンテナの脱走やホストの侵害リスクを低減できます。
ユーザー名前空間の再マッピングに関する 詳細な手順とベストプラクティスについては、Dockerのドキュメントを参照してください。
Kubernetesにおける特権昇格の防止
Kubernetesにおいて、権限昇格を防ぐ最善の方法は、コンテナ作成時に spec.containers.securityContext設定を使用することです。これは、一度過剰な権限を持つコンテナを作成すると、実行時に更新できず、削除して再作成する必要が生じるためです。
以下のセキュリティコンテキストは、前述のようにパッチ未適用のCVE-2022-0492が存在するLinuxバージョンであっても、アプリコンテナを権限昇格から保護します。
コンテナ:
- name: app image: myapp:bullseye-20230912 securityContext:
runAsUser: 1000 # 非rootユーザーIDを使用 runAsGroup: 1000 # 非rootグループIDを使用
runAsNonRoot: true # 明示的に非root実行を強制 allowPrivilegeEscalation: false # プロセスの 権限昇格を 防止 readOnlyRootFilesystem: true # ルートファイルシステムへの書き込みを防止 capabilities:
drop:
- ALL # 攻撃対象領域を最小化するため全権限を削除 add:
- NET_BIND_SERVICE # アプリケーションが必要とする機能のみを再追加 seccompProfile:
type: RuntimeDefault # コンテナランタイムのデフォルトseccompプロファイルを使用Kubernetesにおける権限昇格を防ぐもう一つの優れた方法は、セキュリティコンテキストを持たないPodがスケジューリングされないようにすることです。Kubernetesのアドミッションコントローラーを使用すると、APIサーバーへのリクエスト(例:デプロイメント)をインターセプトし、処理前に特定の条件が満たされていることを検証できます。
より高度なユースケースでは、アドミッションコントローラーを一から記述することも可能です。ただし、 Kyvernoのようなオープンソースソリューションを利用すれば、セキュリティコンテキストが設定されていないデプロイメントを修正できるクラスター全体のポリシーを記述できます。典型的な例は以下のようになります:
apiVersion: kyverno.io/v1kind:ClusterPolicymetadata:
name: add-default-securitycontext annotations:
policies.kyverno.io/title: Add Default securityContext
policies.kyverno.io/category: Sample
policies.kyverno.io/subject: Pod
policies.kyverno.io/minversion: 1.6.0
policies.kyverno.io/description: >-
Pod securityContext エントリは、 Pod を実行する際に使用するユーザーやグループなどのフィールド を定義します 。
ユーザー に対して ブロックする代わりに デフォルト 値 を選択することは 、 Pod 定義を妨げないためのより良い選択肢となる 場合があります 。 このポリシーは、 Pod securityContext内の `runAsNonRoot`、 `runAsUser`、 `runAsGroup`、`fsGroup` フィールドが未設定の場合 、それら を設定するためにPodをmutateします 。spec:
rules:
- name: add-default-securitycontext match:
any:
- resources:
kinds:
rules:
- name:add-default-securitycontext match:
any:
- resources:
kinds:
- Pod mutate:
patchStrategicMerge:
spec:
securityContext:
+(runAsNonRoot): true
+(runAsUser): 1000
+(runAsGroup): 3000
+(fsGroup): 2000上記のマニフェストは、ClusterPolicyカスタムリソース定義(CRD)を使用し、mutate.PatchStrategicMergeおよび非rootユーザーによるセキュリティコンテキストを介してポッドをパッチ適用します。
安全なコンテナは構築されるものであり、想定されるものではない
コンテナはアプリケーションの構築と実行に分離性と信頼性を提供しますが、コンテナセキュリティの絶えず変化する性質上、予防策のみに依存することはできません。代わりに、インシデント発生時に迅速に対応できる戦略を採用すべきです。
その戦略は、積極的なスキャンから始まる。
Aikido、コンテナイメージを自動的にスキャンし、脆弱なパッケージ、古いランタイム、危険なDockerfileの指示を本番環境に到達する前に発見できます。そのオープンソース依存関係スキャナーは、悪用可能なCVEや、攻撃者が特権昇格に利用する可能性のあるサイレントパッチ適用済み脆弱性までライブラリをチェックすることで、この保護機能を拡張します。
これらのスキャンは、安全でないKubernetesやDocker設定を検出するIaCおよび構成チェック、ならびにパイプラインレベルで最小権限ポリシーを強制するCI/CDセキュリティゲートによって強化されています。そして、予防策が完璧であることは決してないため、 Aikido Zen は、異常なコンテナ動作をリアルタイムで検知・対応するランタイム保護を追加します。
今すぐソフトウェアを保護しましょう


.avif)
