Amazon Web Services ブログ

Amazon EKS での Kyverno によるワンツースリーのように簡単なポリシー管理

本記事は、Easy as one-two-three policy management with Kyverno on Amazon EKS を翻訳したものです。

この投稿は、Raj Seshadri と Jimmy Ray によって寄稿されました。

クラウドネイティブな本番環境でコンテナが使用されるようになると、DevOps やセキュリティチームは、コンテナのアクティビティをリアルタイムで可視化し、ホストやネットワークリソースへのコンテナアクセスを制限し、実行中のコンテナに対する脆弱性の悪用に代表されるような攻撃を検出して防止する必要があります。

Kyverno は、ユーザーがプログラミング言語を習得する必要のない Kubernetes 用のポリシーエンジンです。Kyverno は、Kubernetes クラスターにポリシー対応のガバナンスとコンプライアンスを適用するための、直感的で Kubernetes ネイティブな手段を提供します。

ユースケース

今日まで、リアルタイムのコンテナランタイムセキュリティは、そのベストプラクティスを実装するオープンソースツールが限られているために、敷居が高いものでした。Kyverno は、API オブジェクトが変更されたときに Webhook イベントを受信するアドミッションコントローラーとしてインストールされます。この記事では、Kubernetes クラスターの管理者が構成を検証および変更する方法を紹介します。これらはすべて、Rego や他の言語を知らなくても可能です。Kyverno は、EKS クラスター上でポリシー管理をシンプルかつ簡単にしてくれます。

前提条件

すでに EKS または類似の Kubernetes クラスターが稼働していることを前提とします。例えば、このリンクをたどって Amazon EKS の使用を開始することができます。注意: k8s クラスターのバージョンは v1.14 以上である必要があります。このバージョンには Webhook のタイムアウトが追加されています。kubectl version を実行して確認してください。

ステップ 1: かんたんインストール

Kyverno のインストールは簡単です。インストールプロセスの出力は以下のようになります。

kubectl create -f https://raw.githubusercontent.com/kyverno/kyverno/master/definitions/release/install.yaml
namespace/kyverno created
customresourcedefinition.apiextensions.k8s.io/clusterpolicies.kyverno.io created
customresourcedefinition.apiextensions.k8s.io/clusterpolicyviolations.kyverno.io created
customresourcedefinition.apiextensions.k8s.io/generaterequests.kyverno.io created
customresourcedefinition.apiextensions.k8s.io/policies.kyverno.io created
customresourcedefinition.apiextensions.k8s.io/policyviolations.kyverno.io created
serviceaccount/kyverno-service-account created
clusterrole.rbac.authorization.k8s.io/kyverno:customresources created
clusterrole.rbac.authorization.k8s.io/kyverno:generatecontroller created
clusterrole.rbac.authorization.k8s.io/kyverno:policycontroller created
clusterrole.rbac.authorization.k8s.io/kyverno:userinfo created
clusterrole.rbac.authorization.k8s.io/kyverno:webhook created
clusterrole.rbac.authorization.k8s.io/kyverno:admin-policies created
clusterrole.rbac.authorization.k8s.io/kyverno:edit-policies-policyviolations created
clusterrole.rbac.authorization.k8s.io/kyverno:policyviolations created
clusterrole.rbac.authorization.k8s.io/kyverno:view-clusterpolicyviolations created
clusterrole.rbac.authorization.k8s.io/kyverno:view-policies-policyviolations created
clusterrolebinding.rbac.authorization.k8s.io/kyverno:customresources created
clusterrolebinding.rbac.authorization.k8s.io/kyverno:generatecontroller created
clusterrolebinding.rbac.authorization.k8s.io/kyverno:policycontroller created
clusterrolebinding.rbac.authorization.k8s.io/kyverno:userinfo created
clusterrolebinding.rbac.authorization.k8s.io/kyverno:webhook created
configmap/init-config created
service/kyverno-svc created
deployment.apps/kyverno created

ステップ 2: 設定の検証のデモ

特権 (Privileged) コンテナの使用は、理想的なセキュリティの実践ではありません。これは、コンテナにホストが実行できるすべての機能を許可することになります。例えば、侵入されたコンテナが特権を持っていると、不正なコンテナを生成したり、ホスト上で実行されている他のコンテナを詮索したりすることができます。このデモでは、特権を要求する Pod を許可しないポリシーを追加する方法を紹介します。最初のステップは、以下に示すようなポリシーを作成して適用することです。Kyverno は、EKS クラスター内でダイナミックアドミッションコントローラーとして動作します。この場合、Kyverno は、API サーバーから Validating Admission Webhook 呼び出しを受け取り、一致するポリシーを適用してアドミッションポリシーを強制したり、リクエストを拒否したりします。また、Kyverno は既存の Kubernetes リソースのポリシー違反も報告します。

まず、ポリシーを作成しましょう。 以下に示すような disallow_privileged.yaml という YAML ファイルを作成します。 このポリシーでは、特権モードでのプロセスの実行を許可しません。

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-privileged
  annotations:
    policies.kyverno.io/category: Security
    policies.kyverno.io/description: Privileged containers are defined as any
      container where the container uid 0 is mapped to the host’s uid 0.
      A process within a privileged container can get unrestricted host access.
      With `securityContext.allowPrivilegeEscalation` enabled, a process can
      gain privileges from its parent.
spec:
  validationFailureAction: enforce
  rules:
  - name: validate-privileged
    match:
      resources:
        kinds:
        - Pod
    validate:
      message: "Privileged mode is not allowed. Set privileged to false"
      pattern:
        spec:
          containers:
          - =(securityContext):
              =(privileged): false
  - name: validate-allowPrivilegeEscalation
    match:
      resources:
        kinds:
        - Pod
    validate:
      message: "Privileged mode is not allowed. Set allowPrivilegeEscalation to false"
      pattern:
        spec:
          containers:
          - securityContext:
              allowPrivilegeEscalation: false

注: 上記のポリシーは “Pod” に適用されますが、Pod コントローラーに対する Kyverno の “自動生成” ルールによって Deployment のポリシーも作成されます。Kyverno はデフォルトでアノテーション pod-policies.kyverno.io/autogen-controllers=DaemonSet,Deployment,Job,StatefulSet,CrobJob を追加します。

➜ kubectl create -f disallow_privileged.yaml
clusterpolicy.kyverno.io/disallow-privileged create

以下のコマンドを実行すると、disallow-privileged ポリシーが作成されていることがわかります (訳注: Kyverno のバージョンによって出力結果が異ります) 。 cpol は、ClusterPolicy の Custom Resource Definition (CRD) で設定されているショートネームです。

➜ kubectl get cpol
NAME                  AGE
disallow-privileged   62s

それでは、以下の YAML ブロックに示すような、特権アクセスを持つ NGINX の Pod を作成してみましょう。

➜ cat nginx-privileged.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-privileged
  labels:
    app: nginx-privileged
spec:
  containers:
  - name: nginx
    image: nginx
    securityContext:
      allowPrivilegeEscalation: true
➜ kubectl create -f nginx-privileged.yaml
Error from server: error when creating "nginx-privileged.yaml": admission webhook "nirmata.kyverno.resource.validating-webhook" denied the request:

resource Pod/default/nginx-privileged was blocked due to the following policies

disallow-privileged:
  validate-allowPrivilegeEscalation: 'Validation error: Privileged mode is not allowed. Set allowPrivilegeEscalation to false; Validation rule validate-allowPrivilegeEscalation failed at path /spec/containers/0/securityContext/allowPrivilegeEscalation/'

上に示されたように、YAML ファイルに allowPrivilegeEscalation: true が含まれているため、Pod の作成は失敗します。YAML を allowPrivilegeEscalation: false に変更すると、Pod の作成は成功します。これは、Pod 上での特権昇格を許可すべきではないというセキュリティベストプラクティスの一つです。

ステップ 3: 不明なイメージレジストリを許可しないデモ

アドミッションコントローラーを使用して、Kyverno のルールで不明なイメージレジストリからのイメージをブロックすることができます。このサンプルポリシーでは、すべてのイメージが k8s.gcr.io または gallery.ecr.aws のいずれかからのものであることを要求します。このポリシーをカスタマイズして、信頼できる他の異なるイメージレジストリを許可できます。

以下のポリシーを unknown-image-registry.yaml という名前で作成しましょう。

➜ cat unknown-image-registry.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: deployment-pod-valid-registry
  labels:
    app: kyverno
  annotations:
    policies.kyverno.io/category: Compliance
    policies.kyverno.io/description: Rules to enforce correct image source registry
spec:
  validationFailureAction: enforce
  rules:
  - name: validate-registries
    match:
      resources:
        kinds:
        - Pod
    validate:
      message: "Unknown image registry"
      pattern:
        spec:
          containers:
          - image: "k8s.gcr.io/* | gallery.ecr.aws/*"

上記のポリシーをテストするために、以下のような mongo:latest の Pod を作成しましょう。Docker Hub からイメージを Pull していますが、承認されたレジストリではないため、イメージの Pull が失敗するはずです。

➜ cat mongo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: mongo
  labels:
    app: mongo
spec:
  containers:
  - name: mongo
    image: mongo:latest

上記の YAML は、以下のように不明なイメージレジストリのエラーにより失敗します。

Error from server: error when creating "mongo.yaml": admission webhook "nirmata.kyverno.resource.validating-webhook" denied the request:

resource Pod/default/mongo was blocked due to the following policies

deployment-pod-valid-registry:
validate-registries: 'Validation error: Unknown image registry; Validation rule validate-registries failed at path /spec/containers/0/image/'

ArgoCD を使用したポリシーの自動化

DevOps の世界では、常に自動化を念頭に置く必要があります。ご使用の環境でこれらのポリシーを管理および維持するための最良の方法は、GitOps ツールを使用することです。GitOps パターンを適用する CD ツール である ArgoCD を使って、上記の Kyverno のポリシーのすべてを自動化する必要があります。このセクションでは、ArgoCD を使用してコンテナセキュリティのコアとなるベストプラクティスのいくつかを実装する方法を紹介します。EKS クラスターに ArgoCD をインストールするには、このリンクを参照してください (訳注: ArgoCD のインストールの前に、kubectl delete cpol --all を実行し、ここまでに作成した ポリシーを削除してください) 。ArgoCD をインストールしたら、UI にログインして、以下に示すように “New App” をクリックします。

以下に示すように Kyverno アプリの詳細を入力します。サンプル YAML ファイルは https://github.com/texanraj/kyverno/tree/master/samples/core_best_practices にあります。

このステップの後、以下に示すように “Sync” と “Synchronize” をクリックします。これにより、画像の右側に表示されているすべての Kyverno ポリシーが実装されます (訳注: “自動生成” ルールによってマニフェストに変更が加えられるため、ステータスは OutOfSync となりますが、このウォークスルーに影響はないため先に進んでください) 。

これは、以下のように ClusterPolicy (cpol) を照会することで確認できます。

➜ kubectl get cpol
NAME                         AGE
disallow-bind-mounts         37s
disallow-docker-sock-mount   37s
disallow-helm-tiller         37s
disallow-host-network-port   37s
disallow-new-capabilities    37s
disallow-privileged          37s
disallow-root-user           37s
disallow-sysctls             37s
require-ro-rootfs            37s

EKS クラスター内の即時のポリシー違反を把握するには、以下のように PolicyViolation を照会して、問題のあるリソースをレポートします。例えば、私の EKS クラスターでは以下の Deployment で PolicyViolation (polv) がありました (訳注: Kyverno 1.3.0+ では、PolicyViolation ではなくPolicyReport を使用します。詳細は PolicyReport に関する Kyverno のドキュメントを参照してください) 。

➜ kubectl get polv
NAME                        POLICY                RESOURCEKIND   RESOURCENAME         AGE
disallow-privileged-9bzrp   disallow-privileged   Deployment     octank-fintech-dev   5m43s
disallow-privileged-jqdq7   disallow-privileged   Deployment     jenkins              5m45s
disallow-root-user-lbzvw    disallow-root-user    Deployment     octank-fintech-dev   7m20s
require-ro-rootfs-8k27x     require-ro-rootfs     Deployment     octank-fintech-dev   6m45s
require-ro-rootfs-pmcmn     require-ro-rootfs     Deployment     jenkins              6m46s

シフトレフトによるオペレーションとユーザーエクスペリエンスの改善

ポリシー対応の Kubernetes では、ミューテーション (変更) とバリデーションのアドミッションコントロールを使用することで、Kubernetes オペレーションの周囲にガードレールを設置することができます。ガードレールは、クラスター内での不要や不正な動作を減らします。また、クラスター運用に関して、考えるべきことを減らしてくれるという副次的な効果も得られます。Kubernetes クラスターと対話してデプロイを行うすべてのユーザーが、Kubernetes の専門家 (SME) ではありません。Pod が期待通りに起動しない場合、ユーザーはしばしば問題のトラブルシューティングの支援のために、クラスターオペレーター/管理者/SME の助けを借ります。Pod 起動の失敗をトラブルシューティングする際に、Pod Security Policy (PSP) のような単純なものが SME のサイクルを消費する可能性があります。

ポリシー対応の Kubernetes は、クラスターの状態が変更される前に判断を行うことで、この負担を軽減します。SME の介入を必要とした PSP の問題は、すべての Pod とコンテナの Spec に正しい SecurityContext の構成が含まれていることを要求することで、なくならないかもしれませんが、減らすことができます。Kubernetes API のリクエストサイクルでこれらの動作を強制するポリシーは、望ましくない状態変更が etcd に適用されるのを防ぎます。クラスターの API サーバーと対話しているエンドユーザーには、リクエストが無効であり、出力メッセージで定義されている理由で失敗したことがすぐに通知されます。このシンプルなプロセスは、ユーザーを教育し、クラスターオペレーター/管理者のサポートの負担を軽減する大きな可能性を秘めています。このモデルでは、ポリシー対応の Kubernetes はセキュリティ制御を強化し、API サーバーへのリクエストのレスポンスとして判断をシフトレフトさせることで、クラスターユーザーのユーザーエクスペリエンスを向上させます。

クリーンアップ

以下のように ArgoCD のデプロイメントを削除します。

kubectl delete -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

以下のように Kyverno を削除します。

kubectl delete -f https://raw.githubusercontent.com/kyverno/kyverno/master/definitions/release/install.yaml

結論

Kyverno プロジェクトは、Kubernetes クラスターに適切な DevSecOps ポリシーを作成するプロセスを合理化します。この記事では、Kyverno を使ってポリシーを作成し、ArgoCD を使って実装することがいかに簡単であるかを説明しました。Custom Resource Definition (CRD) のような Kubernetes ネイティブのコンポーネントを使用することで、新しい構文や新しいポリシー言語を学ぶ必要性が少なくなります。EKS 環境に Kubernetes ネイティブの方法でポリシーを実装および管理することを選択する場合、Kyverno は優れたオプションです。

リファレンス

https://github.com/nirmata/kyverno
https://kyverno.io/docs/

翻訳はプロフェッショナルサービスの杉田が担当しました。