TT Lab
はじめる
学ぶ 学習パス コース

CKS — Kubernetesセキュリティスペシャリスト

セキュリティ設定が実際に塞ぐものを見る

TT Labで続きを見る

このラボはセキュリティが実際に強制されるクラスターで動きます

VMの中に本物のk3sが起動しています。kubeletとcontainerdが実際に動いているため、securityContextに違反したPodは本当に拒否され、読み取り専用のルートは本当に書き込みを防ぎます。

CKSコースのほかのラボはkwokの上で動きます。そこでは違反したPodもそのままRunningになるため、設定を書く練習はできますが、その設定が守られていることを確認する練習はできません。

最初の起動には2分ほどかかります。

目標

セキュリティ統制がいつ、どこで止めるのかを区別します。アドミッションで止まるものとランタイムで止まるものは、症状も直す場所も違います。

なぜ重要なのか

実務で事故が起きるのは、「設定を間違えて書いたこと」ではなく、設定をすべて書いたのに、それが適用されていないことです。後者は静かだからです。

そして、同じ「Podが起動しない」でも、原因は複数の層に散らばっています。

どこで止まるか 症状 直す場所
アドミッション(作成時点) kubectl applyそのものが拒否される ネームスペースのラベル、ポリシー
kubelet(コンテナ作成時) Podは作成され、CreateContainerConfigErrorになる securityContext
ランタイム(プロセスの中) PodはRunningで、アプリケーションだけが失敗する ボリューム、capability

この3つを区別できないと、障害を見るたびに最初から調べ直すことになります。

ステップ

  1. runAsNonRoot: trueを設定したPodで、rootで動くイメージを起動してみてください。拒否の理由を保存し(保存先: /root/cks/nonroot.txt)、正しいPod(good-nonroot)も一緒に起動してください。違反するPodの名前はbad-rootです。
  2. hardenedPodにreadOnlyRootFilesystem: trueを設定し、書き込みが実際に防がれることを確認して、結果を保存してください(保存先: /root/cks/readonly.txt)。一時ファイルを書き込む場所も一緒に与える必要があります。
  3. 同じPodで、capabilityをALLで落とし、allowPrivilegeEscalation: falseを設定してから、その効果を保存してください(保存先: /root/cks/caps.txt)。
  4. lockedネームスペースにPod Security Admissionをrestrictedで設定し、特権Podが作成時点で拒否されることを保存してください(保存先: /root/cks/psa.txt)。
  5. lockedにServiceAccountapp-saとapp-roleを作成して、configmapの読み取りだけを許可してください。結果を保存します(保存先: /root/cks/rbac.txt)。
  6. app-secretを作成してPodにマウントし、Podの中でそのファイルがどのような姿をしているかを確認して、結果を保存してください(保存先: /root/cks/secret.txt)。
  7. 監査ポリシーを書いてください(保存先: /root/cks/audit-policy.yaml)。最初のルールで、coreのsecrets・configmaps・serviceaccounts/tokenを、ユーザー・動詞・ネームスペースの制限なしでMetadataとして保護してください。次は、/healthz、/readyz、/livezと、それぞれの/*配下のパスだけをNoneにし、最後は条件なしのMetadataです。omitStagesで省略できるのはRequestReceivedだけです。ルールは全部で3つか、デフォルトの前にRBACの書き込みの詳細ルールを加えた4つを使います。任意の詳細ルールは、rbac.authorization.k8s.ioのroles・rolebindings・clusterroles・clusterrolebindingsに対するcreate・update・patch・delete・deletecollectionだけをRequestResponseで記録します。レベル、最初の一致、本文の保護、ログを残す理由を説明してください(保存先: /root/cks/audit.txt)。このステップはポリシーの作成であり、APIへの適用の証明ではありません。
  8. nonroot_reject_reason=、psa_level=、rbac_denied=の3行と一緒に、いつ、どこで止まるのかをまとめてください(保存先: /root/cks/report.md)。

参考

70分のラボなので、期限が切れる前に+時間で延長してください(最大180分)。セッションが終了すると、作業物が消えます。

rootで動くとそもそも起動しない

runAsNonRoot: trueを設定したPodで、rootで動くイメージを起動してみてください。拒否の理由を保存し(保存先: /root/cks/nonroot.txt)、正しいPod(good-nonroot)も一緒に起動してください。違反するPodの名前はbad-rootです。

runAsNonRoot: trueは、kubeletがコンテナを作成する直前に、イメージのUSERを見て判断します。アドミッションではなくkubeletが止めるというのが要点です。

ルートを読み取り専用にする

hardenedPodにreadOnlyRootFilesystem: trueを設定し、書き込みが実際に防がれることを確認して、結果を保存してください(保存先: /root/cks/readonly.txt)。一時ファイルを書き込む場所も一緒に与える必要があります。

readOnlyRootFilesystem: trueだけを設定すると、一時ファイルを書き込むプログラムが落ちます。emptyDirを一緒に付けてください。

capabilityをすべて落とす

同じPodで、capabilityをALLで落とし、allowPrivilegeEscalation: falseを設定してから、その効果を保存してください(保存先: /root/cks/caps.txt)。

drop: ["ALL"]のあとで、本当に必要なものだけをaddで載せ直します。ほとんどのアプリケーションは、何も必要としません。

作成時点で止める

lockedネームスペースにPod Security Admissionをrestrictedで設定し、特権Podが作成時点で拒否されることを保存してください(保存先: /root/cks/psa.txt)。

ネームスペースにpod-security.kubernetes.io/enforce=restrictedラベルを付けます。これはアドミッションなので、kubectl applyそのものが拒否されます。

必要なものだけを与える

lockedにServiceAccountapp-saとapp-roleを作成して、configmapの読み取りだけを許可してください。結果を保存します(保存先: /root/cks/rbac.txt)。

kubectl auth can-i --as=system:serviceaccount:<ns>:<sa>で、許可と拒否の両方を確認してください。開いているものだけを見るのでは、半分です。

SecretはPodの中でどう見えるか

app-secretを作成してPodにマウントし、Podの中でそのファイルがどのような姿をしているかを確認して、結果を保存してください(保存先: /root/cks/secret.txt)。

ボリュームとしてマウントしたあと、ls -laで中をのぞいてみてください。..dataのシンボリックリンク構造と保存先のメディアが要点です。

何を残すかを選ぶ

監査ポリシーを書いてください(保存先: /root/cks/audit-policy.yaml)。最初のルールで、coreのsecrets・configmaps・serviceaccounts/tokenを、ユーザー・動詞・ネームスペースの制限なしでMetadataとして保護してください。次は、/healthz、/readyz、/livezと、それぞれの/*配下のパスだけをNoneにし、最後は条件なしのMetadataです。omitStagesで省略できるのはRequestReceivedだけです。ルールは全部で3つか、デフォルトの前にRBACの書き込みの詳細ルールを加えた4つを使います。任意の詳細ルールは、rbac.authorization.k8s.ioのroles・rolebindings・clusterroles・clusterrolebindingsに対するcreate・update・patch・delete・deletecollectionだけをRequestResponseで記録します。レベル、最初の一致、本文の保護、ログを残す理由を説明してください(保存先: /root/cks/audit.txt)。このステップはポリシーの作成であり、APIへの適用の証明ではありません。

保護ルールが先に一致する必要があります。omitStagesは本文の削除ではありません。ポリシーの作成と、実際の完了イベントの収集を区別してください。

いつ、どこで止まるのか

nonroot_reject_reason=、psa_level=、rbac_denied=の3行と一緒に、いつ、どこで止まるのかをまとめてください(保存先: /root/cks/report.md)。

nonroot_reject_reason=、psa_level=、rbac_denied=の3行と一緒に、アドミッション・kubelet・ランタイムの3つの層をまとめてください。