kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Kubernetes と seccomp を組み合わせてシステムコールを制限する

前回の記事では seccomp (Secure computing mode) に入門するために「Docker と seccomp」を組み合わせて試した.docker run コマンドの --security-opt オプションを使って seccomp プロファイルを指定した.

kakakakakku.hatenablog.com

今回は「Kubernetes と seccomp」を組み合わせて試す.設定や手順などは以下のドキュメントに詳しく載っている.

kubernetes.io

検証環境

まず,kind を使って検証環境を構築する.以下の kind-config.yaml のように,ワーカーノードに seccomp プロファイルを置いたホスト側のディレクトリをマウントする(kubelet に読み込ませる).ドキュメントには ./profiles と書いてあるけど,今回は Docker for Mac を使っていて,マウントできるディレクトリに制限(設定次第)があるため,今回は Mac 側の /tmp/seccomp-profiles に置いた.

apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
nodes:
- role: control-plane
- role: worker
  extraMounts:
  - hostPath: /tmp/seccomp-profiles
    containerPath: /var/lib/kubelet/seccomp/profiles

さっそく kind で Kubernetes クラスターを構築する.準備 OK 💡

$ kind create cluster --config=kind-config.yaml
Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.21.1) 🖼
 ✓ Preparing nodes 📦 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
 ✓ Joining worker nodes 🚜

$ kubectl get nodes
NAME                 STATUS   ROLES                  AGE     VERSION
kind-control-plane   Ready    control-plane,master   2m20s   v1.21.1
kind-worker          Ready    <none>                 113s    v1.21.1

なお,seccompkubelet に設定する.以下のドキュメントを見ると,--seccomp-profile-root オプションに関する記載がある.Kubernetes 1.23 から /seccomp ディレクトリに変更すると書いてあり,覚えておこう!

kubernetes.io

検証 : mkdir システムコールを制限する

前回の記事と同じく Ubuntu で mkdir システムコールを制限して,mkdir コマンドの挙動を確認する.まず,何も指定せず,デフォルト設定のまま Pod で Ubuntu を起動する.

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu
spec:
  containers:
    - name: ubuntu
      image: ubuntu:21.10
      command:
        - sleep
        - infinity

kubectl exec コマンドで Pod に接続をして,問題なく mkdir コマンドを実行できる.

$ kubectl apply -f ubuntu.yaml
pod/ubuntu created

$ kubectl exec -it ubuntu -- /bin/sh

# mkdir sample-dir

次に seccomp プロファイルを指定した Pod で Ubuntu を起動する.前回の記事と同じく Docker (Moby) のデフォルトプロファイルから mkdir システムコールのエントリーを削除した deny-mkdir.json を作る.

$ diff -u default.json deny-mkdir.json
@@ -200,7 +200,6 @@
                "membarrier",
                "memfd_create",
                "mincore",
-               "mkdir",
                "mkdirat",
                "mknod",
                "mknodat",

そして以下のように spec.securityContext.seccompProfileseccomp プロファイルを指定する.プロファイルはワーカーノードにマウントしているため,参照できるようになっている.なお,ドキュメントにも書いてあるけど,Kubernetes v1.19 より前はアノテーションとして annotations.seccomp.security.alpha.kubernetes.io/podseccomp プロファイルを指定していた.今後は spec.securityContext.seccompProfile を使う.

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-deny-mkdir
spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: profiles/deny-mkdir.json
  containers:
    - name: ubuntu
      image: ubuntu:21.10
      command:
        - sleep
        - infinity

同じく kubectl exec コマンドで Pod に接続をすると,今度は mkdir コマンドを実行できなくなった.実際に Operation not permitted とエラーになった.

$ kubectl apply -f ubuntu-deny-mkdir.yaml
pod/ubuntu-deny-mkdir created

$ kubectl exec -it ubuntu-deny-mkdir -- /bin/sh

# mkdir sample-dir
mkdir: cannot create directory 'sample-dir': Operation not permitted

RuntimeDefault プロファイル

さっきは spec.securityContext.seccompProfile.typeLocalhost を指定したけど,他にも spec.securityContext.seccompProfile.typeRuntimeDefault を指定することができる.これはコンテナランタイム側のデフォルトプロファイルを設定することになる.Docker for Mac なら containerd あたり?

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-runtime-default
spec:
  securityContext:
    seccompProfile:
      type: RuntimeDefault
  containers:
    - name: ubuntu
      image: ubuntu:21.10
      command:
        - sleep
        - infinity

kubernetes.io

実際に動作確認をすると問題なく mkdir コマンドを実行することができた.最低限 RuntimeDefault を設定しておくと良さそう.

$ kubectl apply -f ubuntu-runtime-default.yaml
pod/ubuntu-runtime-default created

$ kubectl exec -it ubuntu-runtime-default -- /bin/sh

# mkdir sample-dir

seccomp アクション SCMP_ACT_LOG

ドキュメントを読んでいたら,システムコールを洗い出すための seccomp アクションとして SCMP_ACT_LOG の例が紹介されていた.実際にシステムコールを制限することはせず,syslog にログとして書き出せる.調査目的なら使えそう.

{
    "defaultAction": "SCMP_ACT_LOG"
}

お掃除

検証が終わったら Kubernetes クラスターを削除しておく.

$ kind delete cluster

まとめ

コンテナワークロードのセキュリティ対策として,前回の「Docker と seccomp」の組み合わせに続き「Kubernetes と seccomp」の組み合わせを試した.Podspec.securityContext には他にも多くの設定項目があるため,一歩一歩学んでいくぞ!