kakakakakku blog

Weekly Tech Blog : Keep on Learning 👍

Pod でルートファイルシステムを読み取り専用にする securityContext.readOnlyRootFilesystem

Kubernetes で Pod(正確にはコンテナ単位)に securityContext.readOnlyRootFilesystem: true を設定すると,ルートファイルシステムを読み取り専用にして書き込み操作を抑止できる.アプリケーションのセキュリティ対策として使える.補足をすると Kubernetes 固有の機能ではなく,Docker にも docker run コマンドに --read-only オプションが用意されている.

securityContext:
  readOnlyRootFilesystem: true

検証 : BusyBox

まず securityContext.readOnlyRootFilesystem: true を設定して BusyBox を起動するサンプルマニフェストを作る.

apiVersion: v1
kind: Pod
metadata:
  name: busybox
spec:
  containers:
  - name: busybox
    image: busybox:1.34
    command: ['sh', '-c', 'sleep 3600']
    securityContext:
      readOnlyRootFilesystem: true

実際に Pod を起動して,書き込み操作(とファイル削除)をすると Read-only file system というエラーになった.

$ kubectl apply -f busybox.yaml 
$ kubectl exec -it busybox -- /bin/sh

/ # touch hello.txt
touch: hello.txt: Read-only file system

/ # rm /bin/sh
rm: remove '/bin/sh'? y
rm: can't remove '/bin/sh': Read-only file system

検証 : nginx

次は securityContext.readOnlyRootFilesystem: true を設定して nginx を起動するサンプルマニフェストを作る.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.21
    securityContext:
      readOnlyRootFilesystem: true

今度は Pod を起動することができなかった.Pod のログを確認すると Read-only file system というエラーで nginx を起動すらできていなかった.実際にアプリケーションに securityContext.readOnlyRootFilesystem: true を設定するのは簡単ではなく,書き込みをする可能性のあるディレクトリを洗い出しておく必要がある.

$ kubectl apply -f nginx.yaml 

$ kubectl logs nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: can not modify /etc/nginx/conf.d/default.conf (read-only file system?)
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2022/04/13 00:00:00 [emerg] 1#1: mkdir() "/var/cache/nginx/client_temp" failed (30: Read-only file system)
nginx: [emerg] mkdir() "/var/cache/nginx/client_temp" failed (30: Read-only file system)

nginx の例だと,Docker Hub の nginx ドキュメントに載っている Running nginx in read-only mode が参考になる.デフォルト構成の nginx では /var/cache/var/run に書き込み操作をすると書いてある.他にもログを確認しながらサンプルマニフェストを修正する.

hub.docker.com

最終的に以下のサンプルマニフェストでうまく Pod を起動できるようになった.今回は emptyDir でボリュームを作って,以下の 3 ディレクトリにマウントした.

  • /etc/nginx/conf.d
  • /var/cache/nginx
  • /var/run
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.21
    securityContext:
      readOnlyRootFilesystem: true
    volumeMounts:
      - name: etc-nginx
        mountPath: /etc/nginx/conf.d
      - name: var-cache
        mountPath: /var/cache/nginx
      - name: var-run
        mountPath: /var/run
  volumes:
    - name: etc-nginx
      emptyDir: {}
    - name: var-cache
      emptyDir: {}
    - name: var-run
      emptyDir: {}

参考 : EKS Best Practices Guides

EKS Best Practices Guides にも securityContext.readOnlyRootFilesystem: true を設定する件が載っている.

aws.github.io