CL LAB

HOME > CL LAB > k0sでSeccompを使ってみよう #k0s #mirantis #kubernetes #k8s #seccomp

k0sでSeccompを使ってみよう #k0s #mirantis #kubernetes #k8s #seccomp

 ★ 7

k0sとは、軽量かつ使いやすい、100%オープンソースのKubernetesディストリビューションです。主な特徴としては、

  • フル機能のKubernetesを構築するために必要なすべてを単一バイナリに同梱
  • k0s特有の改変を加えていない、CNCF認定の純正なKubernetesをデプロイ
  • 最低必要リソース1vCPU・1GBメモリ・2GBストレージのシングルノードから、HA構成の大規模クラスタまでサポート
  • Konnectivityをデフォルトで有効化

などが挙げられます。より詳しい情報は公式ドキュメントをご覧ください。

本稿ではこのk0sで、「Dockerが採用するセキュリティ機構「Seccomp」とは何か?」で触れたSeccompを有効にしてみます。

Seccompとは

Seccompとは、Linuxカーネルが持つセキュリティ機構の一つで、Secure Computing Modeの略です。簡単に言うと、Seccompはシステムコールの許可・不許可を設定できるようにし、危険なシステムコールを実行できなくするためのものです。

詳しくは「Dockerが採用するセキュリティ機構「Seccomp」とは何か?」をご覧ください。

containerdにおけるSeccomp

containerd (およびrunc)もSeccompに対応しており、Dockerの場合と同じように利用することができます。k0sでのSeccompを見てみる前に、containerdの場合を見てみましょう。containerdのバージョンは1.3.9です。

[vagrant@master ~]$ sudo ctr version
Client:
  Version:  1.3.9
  Revision: ea765aba0d05254012b0b9e595e995c09186427f
 
Server:
  Version:  1.3.9
  Revision: ea765aba0d05254012b0b9e595e995c09186427f
  UUID: db4bdc57-8218-47ed-8d3d-4fa57f323382

まずstraceコマンドを実行できるsjourdan/straceイメージを取得します。

[vagrant@master ~]$ sudo ctr image pull docker.io/sjourdan/strace:latest
(略)

ctr runコマンドに特にオプションを付与せずに実行するとSeccompは無効なので、straceコマンドは正常に実行できます。

[vagrant@master ~]$ sudo ctr run -t --rm docker.io/sjourdan/strace:latest strace /bin/sh
/ # strace ls -l
execve("/bin/ls", ["ls", "-l"], [/* 5 vars <em>/]) = 0
arch_prctl(ARCH_SET_FS, 0x7f28dfe16b48) = 0
set_tid_address(0x7f28dfe16b80)         = 9
mprotect(0x7f28dfe13000, 4096, PROT_READ) = 0
mprotect(0x560dc8877000, 16384, PROT_READ) = 0
getuid()                                = 0
ioctl(0, TIOCGWINSZ, {ws_row=24, ws_col=80, ws_xpixel=0, ws_ypixel=0}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=24, ws_col=80, ws_xpixel=0, ws_ypixel=0}) = 0
lstat(".", {st_mode=S_IFDIR|0755, st_size=18, ...}) = 0
open(".", O_RDONLY|O_DIRECTORY|O_CLOEXEC) = 3
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
getdents64(3, /</em> 18 entries */, 2048)   = 440
lstat("./bin", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("./dev", {st_mode=S_IFDIR|0755, st_size=360, ...}) = 0
lstat("./etc", {st_mode=S_IFDIR|0755, st_size=17, ...}) = 0
(略)

ctr runコマンドに「--seccomp」オプションを付与してコンテナを起動すると、Seccompが有効になります。この状態でstraceコマンドを実行してみましょう。

[vagrant@master ~]$ sudo ctr run -t --rm --seccomp docker.io/sjourdan/strace:latest strace /bin/sh
/ # strace ls -l
strace: ptrace(PTRACE_TRACEME, ...): Operation not permitted
+++ exited with 1 +++

想定通り、straceコマンドの実行に失敗しました。Dockerと同じくcontainerdも内蔵のSeccompプロファイルを持っており、デフォルトではptraceシステムコールが禁止されているからです。詳細はこちらをご覧ください。

k0sでのSeccomp

k0sでKubernetesをインストールすると、利用するコンテナランタイムとしてcontainerdも一緒にインストールされます。そしてKubernetesもSeccompに対応しているので、k0sではすぐにSeccompを使うことができます。

Virtualbox/Vagrantで用意した2ノードの仮想マシンにk0sをインストールして確認してみましょう。実際のインストール手順はここでは省略しますので「k0sでKubernetesをVirtualbox/Vagrantにインストールしてみよう」を参照してください。

k0sでKubernetesがインストールできたとして、次のマニフェスト「nginx-with-seccomp.yaml」を準備します。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  securityContext:
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: nginx
    image: nginx:1.20.2

この「sepc.securityContext.seccompProfile.type: RuntimeDefault」に注目してください。これはコンテナランタイムのデフォルトのSeccompプロファイルを適用するという意味です。

Podをデプロイし、straceコマンドが実行できるか見てみます。

vagrant@master:~$ k0s kubectl apply -f nginx-with-seccomp.yaml 
pod/nginx created
vagrant@master:~$ k0s kubectl describe pod nginx
Name:         nginx
Namespace:    default
Priority:     0
Node:         node01/192.168.123.201
Start Time:   Tue, 30 Nov 2021 02:52:29 +0000
Labels:       <none>
Annotations:  kubernetes.io/psp: 00-k0s-privileged
              seccomp.security.alpha.kubernetes.io/pod: runtime/default
Status:       Running
(略)
vagrant@master:~$ k0s kubectl exec -it nginx -- bash
root@nginx:/# apt update && apt install -y strace
(略)
root@nginx:/# strace ls -l
strace: test_ptrace_get_syscall_info: PTRACE_TRACEME: Operation not permitted
strace: ptrace(PTRACE_TRACEME, ...): Operation not permitted
strace: PTRACE_SETOPTIONS: Operation not permitted
strace: detach: waitpid(330): No child processes
strace: Process 330 detached

先のcontainerdでの例で見たように、containerdのデフォルトプロファイルではptraceシステムコールが禁止されているため、想定通りにstraceコマンドが実行できませんでした。

デフォルト以外のSeccompプロファイルを利用したい場合はどうすればよいでしょうか? まずはKubeletが動作している全ワーカーノードの指定の場所にプロファイルを設置する必要があります。今回使用した k0s-v1.22.4+k0s.0-amd64 では /var/lib/kubelet/seccomp/ ディレクトリになります。

Docker組み込みのデフォルトプロファイルをダウンロードし、statxシステムコールを許可リストから削除し、/var/lib/kubelet/seccomp/ ディレクトリに no-statx.json として保存します。

vagrant@node01:~$ wget https://raw.githubusercontent.com/moby/moby/master/profiles/seccomp/default.json
vagrant@node01:~$ sudo mkdir /var/lib/kubelet/seccomp
vagrant@node01:~$ sed '/statx/d' default.json | sudo tee /var/lib/kubelet/seccomp/no-statx.json

vagrant@node01:~$ diff -u default.json /var/lib/kubelet/seccomp/no-statx.json 
--- default.json    2021-11-30 03:54:49.153299783 +0000
+++ /var/lib/kubelet/seccomp/no-statx.json  2021-11-30 03:56:26.385299783 +0000
@@ -351,7 +351,6 @@
                "stat64",
                "statfs",
                "statfs64",
-               "statx",
                "symlink",
                "symlinkat",
                "sync",
vagrant@node01:~$ 

このプロファイルを利用するマニフェストは次のようになります。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: no-statx.json
  containers:
  - name: nginx
    image: nginx:1.20.2

「sepc.securityContext.seccompProfile.type: Localhost」と「sepc.securityContext.seccompProfile.localhostProfile: no-statx.json」に注目してください。これはワーカーノード上の指定されたSeccompプロファイルを適用するという意味になります。

Podをデプロイし、statxシステムコールを利用するlsコマンドが実行できるか見てみます。

vagrant@master:~$ k0s kubectl apply -f nginx-with-no-statx.yaml 
pod/nginx created
vagrant@master:~$ k0s kubectl describe pod nginx
Name:         nginx
Namespace:    default
Priority:     0
Node:         node01/192.168.123.201
Start Time:   Tue, 30 Nov 2021 03:57:59 +0000
Labels:       <none>
Annotations:  kubernetes.io/psp: 00-k0s-privileged
              seccomp.security.alpha.kubernetes.io/pod: localhost/no-statx.json
Status:       Running
(略)
vagrant@master:~$ k0s kubectl exec -it nginx -- bash
root@nginx:/# ls -l
ls: cannot access 'tmp': Operation not permitted
ls: cannot access 'lib64': Operation not permitted
ls: cannot access 'media': Operation not permitted
ls: cannot access 'etc': Operation not permitted
ls: cannot access 'root': Operation not permitted
ls: cannot access 'opt': Operation not permitted
ls: cannot access 'srv': Operation not permitted
ls: cannot access 'bin': Operation not permitted
ls: cannot access 'dev': Operation not permitted
ls: cannot access 'sys': Operation not permitted
ls: cannot access 'mnt': Operation not permitted
ls: cannot access 'run': Operation not permitted
ls: cannot access 'lib': Operation not permitted
ls: cannot access 'proc': Operation not permitted
ls: cannot access 'home': Operation not permitted
ls: cannot access 'usr': Operation not permitted
ls: cannot access 'sbin': Operation not permitted
ls: cannot access 'boot': Operation not permitted
ls: cannot access 'var': Operation not permitted
ls: cannot access 'docker-entrypoint.d': Operation not permitted
ls: cannot access 'docker-entrypoint.sh': Operation not permitted
total 0
d????????? ? ? ? ?            ? bin
d????????? ? ? ? ?            ? boot
d????????? ? ? ? ?            ? dev
d????????? ? ? ? ?            ? docker-entrypoint.d
-????????? ? ? ? ?            ? docker-entrypoint.sh
d????????? ? ? ? ?            ? etc
d????????? ? ? ? ?            ? home
d????????? ? ? ? ?            ? lib
d????????? ? ? ? ?            ? lib64
d????????? ? ? ? ?            ? media
d????????? ? ? ? ?            ? mnt
d????????? ? ? ? ?            ? opt
d????????? ? ? ? ?            ? proc
d????????? ? ? ? ?            ? root
d????????? ? ? ? ?            ? run
d????????? ? ? ? ?            ? sbin
d????????? ? ? ? ?            ? srv
d????????? ? ? ? ?            ? sys
d????????? ? ? ? ?            ? tmp
d????????? ? ? ? ?            ? usr
d????????? ? ? ? ?            ? var
root@nginx:/# 

想定通り、statxシステムコールが禁止されたので、ファイルの情報が取得できなくなりました。
念のため確認として、同じSeccompプロファイルを適用して、statxではなくlstatシステムコールを利用するlsコマンドが実行できるかも見てみましょう。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: no-statx.json
  containers:
  - name: nginx
    image: nginx:1.20.1

vagrant@master:~$ k0s kubectl apply -f nginx-old-with-no-statx.yaml 
pod/nginx created
vagrant@master:~$ k0s kubectl exec -it nginx -- bash
root@nginx:/# ls -l
total 80
drwxr-xr-x   2 root root 4096 Oct 11 00:00 bin
drwxr-xr-x   2 root root 4096 Oct  3 09:00 boot
drwxr-xr-x   5 root root  360 Nov 30 04:02 dev
drwxr-xr-x   1 root root 4096 Oct 12 02:04 docker-entrypoint.d
-rwxrwxr-x   1 root root 1202 Oct 12 02:04 docker-entrypoint.sh
drwxr-xr-x   1 root root 4096 Nov 30 04:02 etc
drwxr-xr-x   2 root root 4096 Oct  3 09:00 home
drwxr-xr-x   1 root root 4096 Oct 12 02:04 lib
drwxr-xr-x   2 root root 4096 Oct 11 00:00 lib64
drwxr-xr-x   2 root root 4096 Oct 11 00:00 media
drwxr-xr-x   2 root root 4096 Oct 11 00:00 mnt
drwxr-xr-x   2 root root 4096 Oct 11 00:00 opt
dr-xr-xr-x 133 root root    0 Nov 30 04:02 proc
drwx------   2 root root 4096 Oct 11 00:00 root
drwxr-xr-x   1 root root 4096 Nov 30 04:02 run
drwxr-xr-x   2 root root 4096 Oct 11 00:00 sbin
drwxr-xr-x   2 root root 4096 Oct 11 00:00 srv
dr-xr-xr-x  13 root root    0 Nov 30 02:48 sys
drwxrwxrwt   1 root root 4096 Oct 12 02:04 tmp
drwxr-xr-x   1 root root 4096 Oct 11 00:00 usr
drwxr-xr-x   1 root root 4096 Oct 11 00:00 var
root@nginx:/# 

想定通り、正常に動作しました。

まとめ

本稿ではk0sでインストールしたKubernetesに、Seccompを有効にしたPodをデプロイしてみました。
Seccompを有効にすることで、万が一コンテナを乗っ取られた場合でも危険なシステムコールが実行できなくなり、安全性の向上につながります。
セキュアなコンテナが必要な場合は是非おためしください。

CL LAB Mail Magazine

CL LABの情報を逃さずチェックしよう!

メールアドレスを登録すると記事が投稿されるとメールで通知します。

メールアドレス: 登録

※登録後メールに記載しているリンクをクリックして認証してください。

Related post

Neo4j[ホワイトペーパー]CCPA