Kubernetes で readOnlyRootFilesystem の設定がTrue になってないのをデプロイする前にConftest したい

概要

Kubernetes ではポッドセキュリティポリシーにより、ポッドの作成と更新のきめ細かい承認が可能になります。また、Pod に直接設定するだけではなくRBAC を利用したデフォルトの設定を行うことができたり、OPAgatekeepeを利用することで開発者は意識することなくセキュリティの設定を行うことができます。こちらにはreadOnlyRootFilesystemというオプションがあり、このオプションを有効にするとコンテナ内がreadonlyになるためセキュリティの施策の1つとして有効にすべき場面が多いと思います。こちらは有用ですが yamlを作成していざ、本番へというタイミングでしか分からないのは流石にしんどいです。そのため、デプロイの前にこれはテストをすることは無駄ではありません。

readOnlyRootFilesystem をやってみる

apiVersion: v1
kind: Pod
metadata:
  name: read-onlyroot-filesystem
spec:
  containers:
  - name: centos7
    image: centos:7
    command: [ "sh", "-c", "sleep 1h" ]
    securityContext:
      readOnlyRootFilesystem: true
  - name: centos8
    image: centos:8
    command: [ "sh", "-c", "sleep 1h" ]

Podの作成

kubectl apply -f readonly_pod.yaml 
pod/read-onlyroot-filesystem created
kubectl get pod 
NAME                       READY   STATUS    RESTARTS   AGE
read-onlyroot-filesystem   2/2     Running   0          15m

ファイルのWrite 及び Read/Write を実施する

kubectl exec -it read-onlyroot-filesystem -c centos7 touch testfile
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
touch: cannot touch 'testfile': Read-only file system
command terminated with exit code 1
$ kubectl exec -it read-onlyroot-filesystem -c centos7 ls   
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
anaconda-post.log  bin  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
$ kubectl exec -it read-onlyroot-filesystem -c centos7 pwd       
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
/

テストする

gatekeepeポッドセキュリティポリシー をユーザーやNamespace 単位で実施することにより開発者は意識することなくセキュリティの設定を行うことができますがyamlを作成していざ、本番へというタイミングでしか分からないので流石にめんどくさいです。そのため、デプロイの前にこれはテストをすることは無駄ではありません。conftestYAMLJSON などの構造化データに対してユニットテストを記述できるツールです。

install と実行

$ wget https://github.com/open-policy-agent/conftest/releases/download/v0.21.0/conftest_0.21.0_Linux_x86_64.tar.gz
$ tar xzf conftest_0.21.0_Linux_x86_64.tar.gz
$ sudo mv conftest /usr/local/bin

input.spec.containers.securityContext.readOnlyRootFilesystem が正であればこれで通ります。

package main

deny[msg] {
  input.kind == "Pod"
  input.spec.containers.securityContext.readOnlyRootFilesystem
  msg := "Containers must not write"
}

Pass しました

$ conftest test readonly_pod.yaml

1 test, 1 passed, 0 warnings, 0 failures, 0 exceptions

書き込みは許可したい場合はnot input.spec.containers.securityContext.readOnlyRootFilesystemのような設定をぶちこんであげれば良いです。

package main

deny[msg] {
  input.kind == "Pod"
  not input.spec.containers.securityContext.readOnlyRootFilesystem
  msg := "Containers must write"
}

そして、実行すると、想定通りに失敗します。事前に分かるというメリットは以外に多くありますのでぜひ、皆さんの環境でも試してみてはいかがでしょうか?

conftest test readonly_pod.yaml
FAIL - readonly_pod.yaml - Containers must write

1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions