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

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

イメージの固定と出所の統制

TT Labで続きを見る

目標

クラスターに入ってくるイメージをダイジェストで固定し、出所を許可リストで絞り込み、プライベートレジストリの認証をServiceAccountのレベルで処理する、標準的な構成を作ります。

なぜ重要なのか

タグは変更可能なポインターです。同じv1.2タグに別のイメージをプッシュでき、そうすると、昨日検証したイメージと今日動いているイメージが違う可能性があります。ダイジェストは内容のハッシュなので、この問題を根本からなくします。事故が起きたときに「いま動いているものは正確には何か」にすぐ答えられるかどうかが、対応時間を左右します。

出所の統制はその次です。許可レジストリの一覧は、ポリシーエンジンのパラメーターにそのまま入り、imagePullSecretsはそのレジストリにアクセスするための認証情報です。Podごとに書くより、ServiceAccountに付けておけば、新しいワークロードが自動的に継承するため、漏れが減ります。

この環境にはインターネットがないため、実際にイメージを取得することも、KyvernoのようなポリシーエンジンのCRDをインストールすることもできません。そのため、ポリシーのマニフェストはファイルとして書いて採点し、残りは実際のオブジェクトで採点します。

ステップ

  1. ネームスペースcks-supplyを作成し、その中にPodpinnedを作成してください。イメージはタグなしで、ダイジェストで固定します(registry.cks.local/shop/api@sha256:の後ろに64桁の16進数)。imagePullPolicyはIfNotPresentにします。
  2. /root/cks-supply-chain/allowed-registries.txtに、許可レジストリのprefixを1行に1つずつ、次の順序のとおりに4行書いてください。registry.cks.local/、harbor.cks.local/library/、registry.k8s.io/、ghcr.io/cks-lab/
  3. cks-supplyにkubernetes.io/dockerconfigjsonタイプのSecretharbor-pullを作成してください。サーバーはharbor.cks.local、ユーザーはrobot$cks、パスワードはcks-lab-tokenにします。
  4. cks-supplyにServiceAccountdeployerを作成し、そのimagePullSecretsにharbor-pullを入れてください。
  5. /root/cks-supply-chain/verify-images.yamlに、署名検証ポリシーのマニフェストを書いてください。apiVersion: kyverno.io/v1、kind: ClusterPolicyで、名前はverify-image-signature、spec.validationFailureActionはEnforceとし、ルール1つ(spec.rules[0].nameはcheck-signature)が、verifyImages[0].imageReferences[0]でregistry.cks.local/*を対象にします。
  6. cks-supplyにPodlegacy-web(イメージnginx:latest)を作成して、固定されていないワークロードを再現してください。そのあと、/root/cks-supply-chain/find-unpinned.shに検知スクリプトを書き、実行結果を/root/cks-supply-chain/unpinned.txtに保存してください。結果は、cks-supplyネームスペースで、イメージが@sha256:で固定されていないコンテナを持つPodを、cks-supply/<파드이름>形式(プレースホルダーはPod名です)で、辞書順に並べて1行に1つずつ入れたものです。
  7. cks-supplyにDeploymentcheckoutを作成してください。replicasは2、セレクターとPodラベルはapp=checkout、serviceAccountNameはdeployer、コンテナ名はapp、イメージはregistry.cks.local/で始まり、@sha256:で固定されたもの、imagePullPolicyはIfNotPresentにします。

参考

タグの代わりにダイジェストで固定する

ネームスペースcks-supplyを作成し、その中にPodpinnedを作成してください。イメージはタグなしで、ダイジェストで固定します(registry.cks.local/shop/api@sha256:の後ろに64桁の16進数)。imagePullPolicyはIfNotPresentにします。

イメージの参照は<레지스트리>/<이름>@sha256:<64자리 16진수>の形です(プレースホルダーはレジストリ、イメージ名、64桁の16進数です)。タグとダイジェストを併記せず、ダイジェストだけを残してください。

許可レジストリの一覧

/root/cks-supply-chain/allowed-registries.txtに、許可レジストリのprefixを1行に1つずつ、次の順序のとおりに4行書いてください。registry.cks.local/、harbor.cks.local/library/、registry.k8s.io/、ghcr.io/cks-lab/

ポリシーエンジンのパラメーターにそのまま渡される一覧です。prefixの形で書き、末尾にスラッシュを付けないと、名前の似た別のレジストリが通過してしまいます。

レジストリ認証のSecret

cks-supplyにkubernetes.io/dockerconfigjsonタイプのSecretharbor-pullを作成してください。サーバーはharbor.cks.local、ユーザーはrobot$cks、パスワードはcks-lab-tokenにします。

kubectl create secret docker-registryの1行で済みます。タイプ名はkubernetes.io/dockerconfigjsonで、データのキーは.dockerconfigjsonです。

ServiceAccountにpull Secretを付ける

cks-supplyにServiceAccountdeployerを作成し、そのimagePullSecretsにharbor-pullを入れてください。

ServiceAccountのimagePullSecretsに入れておけば、そのSAを使うすべてのPodが自動的に認証されます。Podごとに書くより優れています。

署名・SBOM検証ポリシーのマニフェスト

/root/cks-supply-chain/verify-images.yamlに、署名検証ポリシーのマニフェストを書いてください。apiVersion: kyverno.io/v1、kind: ClusterPolicyで、名前はverify-image-signature、spec.validationFailureActionはEnforceとし、ルール1つ(spec.rules[0].nameはcheck-signature)が、verifyImages[0].imageReferences[0]でregistry.cks.local/*を対象にします。

このクラスターにはポリシーエンジンのCRDがないため、ファイルとしてのみ書きます。imageReferencesで対象のレジストリを選び、attestorsに公開鍵を入れる構造です。

ダイジェスト未固定のPodを検知する

cks-supplyにPodlegacy-web(イメージnginx:latest)を作成して、固定されていないワークロードを再現してください。そのあと、/root/cks-supply-chain/find-unpinned.shに検知スクリプトを書き、実行結果を/root/cks-supply-chain/unpinned.txtに保存してください。結果は、cks-supplyネームスペースで、イメージが@sha256:で固定されていないコンテナを持つPodを、cks-supply/<파드이름>形式(プレースホルダーはPod名です)で、辞書順に並べて1行に1つずつ入れたものです。

イメージの文字列に@sha256:がなければ、未固定です。jqのcontainsやtestで絞り込めます。initコンテナも一緒に見る必要があります。

総合: 固定・認証・出所をすべて備えたデプロイ

cks-supplyにDeploymentcheckoutを作成してください。replicasは2、セレクターとPodラベルはapp=checkout、serviceAccountNameはdeployer、コンテナ名はapp、イメージはregistry.cks.local/で始まり、@sha256:で固定されたもの、imagePullPolicyはIfNotPresentにします。

先に作成したServiceAccountと、許可レジストリの一覧の最初のprefixをそのまま使います。イメージはダイジェストで固定し、imagePullPolicyも一緒に指定してください。