Skip to main content

Kubernetes securityContext:KubernetesにおけるLinux capabilities

Kubernetes securityContext

2021年1月26日

0 分で読めます

はるか昔、Unixオペレーティングシステムの権限モデルは比較的シンプルでした。通常のユーザーか、あらゆる操作を実行できる権限を持つスーパーユーザー、rootのどちらかでした。

通常のユーザーにファイルやディレクトリへの昇格した権限を与えることはできましたが、ほぼすべてのカーネルレベルの機能はrootユーザーに制限されていました。アプリケーションの動作にカーネルレベルの呼び出しが1つでも必要な場合、SUID権限を与える必要がありました。これは実質的に、通常のユーザーが起動した場合でも、そのプロセスにroot権限を付与することになります。

物理マシンを比較的少数のユーザーで利用していた時代には、この仕組みで十分に機能していました。しかし、この大まかな権限の区分は、現代の用途には適していませんでした。柔軟性とセキュリティを高めるため、Linuxカーネルの開発者は、カーネルレベルの呼び出しをケイパビリティにまとめ、個々のプロセスに割り当てられる、よりきめ細かな仕組みを考案しました。これにより、アプリケーションが必要とするカーネル呼び出しが1つだけなら、そのケイパビリティだけを割り当て、システムがさらされるセキュリティリスクを抑えられるようになりました。

Kubernetesコンテナの権限管理

では、コンテナではどのように機能するのでしょうか?

コンテナは、カーネルのcgroupと名前空間を使って分離された、システム上で実行されるプロセスにすぎません。そのため、ほかのプロセスと同じようにコンテナにもケイパビリティを割り当てられます。コンテナの作成時に、コンテナランタイムがこの処理を行います。

通常、コンテナランタイムはコンテナに既定のケイパビリティ一式を割り当て(Dockerが提供する既定のセットはこちらで確認できます)、ケイパビリティを追加または削除する仕組みも提供します。コンテナを--privilegedフラグ付きで実行すると、すべてのケイパビリティがコンテナに付与されます。コンテナをrootとして実行している場合、深刻なセキュリティ問題につながるおそれがあります。この点については、以前の記事で取り上げました。

KubernetesのsecurityContextでコンテナのケイパビリティを設定する

Kubernetesでコンテナランタイムを使用する際、Kubernetesのコントロールプレーンがこれらの制御機能を使い、コンテナの起動時に付与するケイパビリティを定義します。ケイパビリティの設定は、コンテナのYAMLにあるsecurityContextセクションの各種設定を通じて指定できます。設定例は次のとおりです。

securityContext:
      capabilities:
        drop:
          - ALL
        add: [“NET_ADMIN”]

この例では、すべてのケイパビリティを削除してから、CAP_NET_ADMINを追加します。securityContextのcapabilitiesセクションが空の場合、コンテナランタイムで定義された既定のケイパビリティ一式が適用されます。通常、このセットはかなり広範で、アプリケーションに必要な範囲を大きく超えている可能性があります。KubernetesでPodを起動し、どのケイパビリティが付与されるか確認してみましょう。

まず、PodをデプロイするためのYAMLを作成します。この設定では、Docker Hubのアップストリームイメージを使用します。Alpineベースのこのイメージには、コンテナが持つケイパビリティを確認できるcapshツールが追加されています。

このコンテナにはsecurityContextセクションを定義していないため、各設定にはシステムの既定値が適用されます。Kubernetesでユーザーを指定しない場合、コンテナはビルド元のDockerfileで指定された既定のユーザーとして実行されることを覚えておきましょう。多くのコンテナでは、これがrootです。

% cat caps.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: caps
  labels:
    app: caps
spec:
  containers:
  - name: caps
    image: ollijanatuinen/capsh
    command: ["/bin/sleep", "3650d"]
    imagePullPolicy: IfNotPresent
  restartPolicy: Always

% kubectl apply -f caps.yaml 
pod/caps created

Podが起動したら、その中でシェルを開き、capshを実行してケイパビリティを確認できます。

% kubectl exec --stdin --tty caps -- ash 
/ # capsh --print
Current: = cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap+eip
Bounding set =cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap
Securebits: 00/0x0/1'b0
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)

KubernetesのsecurityContextでケイパビリティを削除する

このように、既定ではrootとして実行され、多くのケイパビリティが付与されています。これはコンテナランタイムで既定として定義されたセットです。次に、securityContextの設定でケイパビリティを1つ削除してみましょう。新しいファイルシステムノードを作成する機能、つまりCAP_MKNODを削除します。

matt@Mattbook capabilities_testing % cat dropcaps.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: dropcaps
  labels:
    app: dropcaps
spec:
  containers:
  - name: dropcaps
    image: ollijanatuinen/capsh
    command: ["/bin/sleep", "3650d"]
    imagePullPolicy: IfNotPresent
    securityContext:
      capabilities:
        drop: ["MKNOD"]
  restartPolicy: Always

% kubectl apply -f dropcaps.yaml 
pod/dropcaps created

% kubectl exec --stdin --tty dropcaps -- ash
/ # capsh --print
Current: = cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_audit_write,cap_setfcap+eip
Bounding set =cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_audit_write,cap_setfcap
Securebits: 00/0x0/1'b0
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)

最初のPodと比べると、このPodではcap_mknodケイパビリティが削除されていることがわかります。個別のケイパビリティだけでなく、securityContextですべてのケイパビリティを削除することもできます。

matt@Mattbook capabilities_testing % cat nocaps.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: nocaps
  labels:
    app: nocaps
spec:
  containers:
  - name: nocaps
    image: ollijanatuinen/capsh
    command: ["/bin/sleep", "3650d"]
    imagePullPolicy: IfNotPresent
    securityContext:
      capabilities:
        drop:
          - ALL
  restartPolicy: Always

matt@Mattbook capabilities_testing % kubectl apply -f nocaps.yaml 
pod/nocaps created

matt@Mattbook capabilities_testing % kubectl exec --stdin --tty nocaps -- ash
/ # capsh --print
Current: =
Bounding set =
Securebits: 00/0x0/1'b0
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)

ケイパビリティがまったくないと、実行に失敗するシステム機能もあります。たとえば、apkを使ってbashをインストールしてみましょう。

/ # apk add bash
(1/5) Installing ncurses-terminfo-base (6.1_p20180818-r1)
(2/5) Installing ncurses-terminfo (6.1_p20180818-r1)
(3/5) Installing ncurses-libs (6.1_p20180818-r1)
(4/5) Installing readline (7.0.003-r0)
(5/5) Installing bash (4.4.19-r1)
Executing bash-4.4.19-r1.post-install
ERROR: bash-4.4.19-r1.post-install: script exited with error 127
Executing busybox-1.28.4-r1.trigger
ERROR: busybox-1.28.4-r1.trigger: script exited with error 127
1 error; 13 MiB in 19 packages

コンテナはrootとして実行されていますが、bashパッケージのインストールに失敗します。ファイルシステムの権限設定が必要なのに、そのケイパビリティをコンテナから削除したためです。コンテナ内でのソフトウェアのインストールを禁止したい場合、ケイパビリティを使って権限を管理する方法が有効です。

capshを使うとコンテナが持つケイパビリティを見やすく表示できますが、確認方法はそれだけではありません。追加のソフトウェアをインストールせずに、procファイルシステムから直接情報を取得することもできます。

/ # cd /proc/1/
/proc/1 # cat status 
----truncated
CapPrm:0000000000000000
CapEff:0000000000000000
CapBnd:0000000000000000
CapAmb:0000000000000000
----truncated

/proc/1/statusファイルでは、ケイパビリティがビットマップで表示されます。このコンテナではケイパビリティを有効にしていないため、すべて0です。すべてのケイパビリティが有効になっている元のコンテナで、同じファイルを確認すると次のようになります。

/ # cd /proc/1/
/proc/1 # cat status 
----truncated
CapInh:00000000a80425fb
CapPrm:00000000a80425fb
CapEff:00000000a80425fb
CapBnd:00000000a80425fb
----truncated

capshの出力ほど読みやすくはありませんが、ここに示された各ビットは、該当するカーネルのヘッダーで定義されている特定のケイパビリティを表しています。

コンテナの既定のケイパビリティを削除する方法について詳しく学び、Kubernetesのセキュリティを強化しましょう。

KubernetesのsecurityContextでケイパビリティを追加する

ケイパビリティは削除するだけでなく、再度追加することもできます。先ほどの例を使い、securityContextの設定にケイパビリティを1つ追加してみましょう。ここでもCAP_MKNODを追加します。

% cat addcaps.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: addcaps
  labels:
    app: addcaps
spec:
  containers:
  - name: addcaps
    image: ollijanatuinen/capsh
    command: ["/bin/sleep", "3650d"]
    imagePullPolicy: IfNotPresent
    securityContext:
      capabilities:
        drop:
          - ALL
        add: ["MKNOD"]
  restartPolicy: Always

% kubectl create -f addcaps.yaml           
pod/addcaps created
% kubectl exec --stdin --tty addcaps -- ash
/ # capsh --print
Current: = cap_mknod+eip
Bounding set =cap_mknod
Securebits: 00/0x0/1'b0
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)

この例では、ケイパビリティが1つだけ有効になっていることがわかります。

KubernetesのsecurityContextにおける最小権限の原則

この記事では、コンテナにおけるケイパビリティの仕組みと、KubernetesのsecurityContextでの設定方法、そしてコンテナランタイムによる制御について説明しました。

最小権限の原則に従うなら、セキュリティのベストプラクティスは、コンテナに実際に必要なケイパビリティだけを付与することです。このテーマについては以前の記事で取り上げました。多くのプロセスでは、カーネルのケイパビリティが実際には必要ないことに驚くかもしれません。昇格した権限が必要な場合でも、その大半はファイルレベルの権限で制御できるためです。

まずsecurityContextですべてのケイパビリティを削除し、必要なものだけを追加していきましょう。SELinuxなどのツールの出力を確認すれば、どのケイパビリティが問題を引き起こしているかを特定し、失敗の原因を調べられます。また、別のユーザーを指定しない限り、Kubernetesのコンテナはrootとして実行される可能性があることにも注意が必要です。

KubernetesのsecurityContextでケイパビリティ設定を徹底する

ケイパビリティや非rootでの実行といったsecurityContextの設定を確実に適用するには、Kubernetesクラスターでアドミッションコントローラーを使い、適切なセキュリティ設定がないコンテナの起動を防ぐことができます。Kubernetesには、securityContextの設定を強制できるPodSecurityPolicyコントローラーが組み込まれています。

ただし、1.21リリースで非推奨になるため、Open Policy Agentなどの外部でメンテナンスされるプロジェクトが推奨されます。

こうしたセキュリティ設定を可視化し、修正する仕組みを開発プロセスに直接組み込むことも重要です。SnykはKubernetesのYAMLファイルをスキャンし、ケイパビリティなどに関する安全でないsecurityContextの設定を検出できるほか、開発者のワークフロー内で修正方法を提案します。この機能はSnyk CLIで利用でき、ソースコード管理システムや継続的インテグレーションにも直接統合できます。

% snyk iac test caps.yaml

Testing caps.yaml...

Infrastructure as code issues:
  ✗ Container is running with default set of capabilities [Medium Severity] [SNYK-CC-K8S-6] in Deployment
    introduced by input > spec > containers[caps] > securityContext > capabilities > drop

  ✗ Container is running without root user control [Medium Severity] [SNYK-CC-K8S-10] in Deployment
    introduced by input > spec > containers[caps] > securityContext > runAsNonRoot

  ✗ Container is running without memory limit [Low Severity] [SNYK-CC-K8S-4] in Deployment
    introduced by input > spec > containers[caps] > resources > limits > memory

  ✗ Container is running without cpu limit [Low Severity] [SNYK-CC-K8S-5] in Deployment
    introduced by input > spec > containers[caps] > resources > limits > cpu

  ✗ Container is running with writable root filesystem [Low Severity] [SNYK-CC-K8S-8] in Deployment
    introduced by input > spec > containers[caps] > securityContext > readOnlyRootFilesystem

  ✗ Container is running without AppArmor profile [Low Severity] [SNYK-CC-K8S-32] in Deployment
    introduced by metadata > annotations['container.apparmor.security.beta.kubernetes.io/caps']

  ✗ Container is running without liveness probe [Low Severity] [SNYK-CC-K8S-41] in Deployment
    introduced by spec > containers[caps] > livenessProbe

  ✗ Container could be running with outdated image [Low Severity] [SNYK-CC-K8S-42] in Deployment
    introduced by spec > containers[caps] > imagePullPolicy

Organization:      matt-jarvis-snyk
Type:              Kubernetes
Target file:       caps.yaml
Project name:      capabilities_testing
Open source:       no
Project path:      caps.yaml

Tested caps.yaml for known issues, found 8 issues
privileged: trueとデフォルトのケイパビリティが設定されたコンテナを示す、Kubernetesのセキュリティコンテキストのコード例

この機能を試してみませんか?今すぐ無料アカウントに登録しましょう。

CTFを始めよう

オンデマンドのバーチャル入門ワークショップで、CTFチャレンジの解き方を学びましょう。

続きを読む

blog feature pypi spoof
Article

オープンソースのメンテナーに、Snyk AI Security Platformをすべて無料で提供

オープンソースのメンテナーは、実際の脆弱性レポートに追われ、優先順位付けや修正、修正版のリリースを迅速に進めるための支援を必要としています。SnykのSecure Developer Programでは、条件を満たすプロジェクトにSnyk AI Security Platformを無料で提供します。

feature insights announcement
Blog

Node-gypサプライチェーン侵害:binding.gypに潜む自己増殖型npmワーム

新たなnpmワームがbinding.gypを悪用し、インストール時にnode-gypを起動。ライフサイクルスクリプトを使わずに悪意あるパッケージからコードを実行します。認証情報を窃取し、GitHub上に潜伏し、メンテナー間で自己増殖します。

Article

メンテナーアカウント侵害が疑われる中、悪意のあるnode-ipcのバージョンがnpmに公開

2026年5月14日、人気のnpmパッケージnode-ipcの複数の悪意あるバージョンがnpmレジストリに公開されました。現在の公開情報では、node...