カスタム制約テンプレートを作成する

このページでは、事前作成された制約テンプレートがニーズに合わない場合にカスタム制約テンプレートを作成し、Policy Controller を拡張する方法について説明します。

このページは、監査または適用のために自動化や、宣言型構成のテンプレート化により、クラウド プラットフォーム内で実行されているすべてのリソースが組織のコンプライアンス要件を確実に満たすようにする IT 管理者とオペレーターを対象としています。Google Cloud のコンテンツで参照する一般的なロールとタスク例の詳細については、一般的な GKE Enterprise ユーザーロールとタスクをご覧ください。

Policy Controller のポリシーは、OPA Constraint Framework を使用して記述され、Rego で作成されています。ポリシーは、Kubernetes オブジェクトのすべてのフィールドを評価できます。

Rego を使用したポリシーの作成は特殊なスキルです。このため、共通の制約テンプレートのライブラリがデフォルトでインストールされます。制約の作成時にこれらの制約テンプレートを呼び出すことができます。特殊なニーズがある場合は、独自の制約テンプレートを作成できます。

制約テンプレートを使用すると、ポリシーのロジックを特定の要件から分離して、再利用や委任を行うことができます。制約の作成は、オープンソース プロジェクト、ソフトウェア ベンダー、規制の専門家など、サードパーティが開発した制約テンプレートを使用して行えます。

始める前に

制約テンプレートの例

以下は、制約の作成者が指定した値と名前が一致するすべてのリソースを拒否する制約テンプレートの例です。このページの残りの部分では、テンプレートの内容について説明します。その過程で、重要なコンセプトについてハイライト表示します。

階層リポジトリで Config Sync を使用している場合は、cluster/ ディレクトリに制約を作成することをおすすめします。

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8sdenyname
spec:
  crd:
    spec:
      names:
        kind: K8sDenyName
      validation:
        # Schema for the `parameters` field
        openAPIV3Schema:
          properties:
            invalidName:
              type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sdenynames
        violation[{"msg": msg}] {
          input.review.object.metadata.name == input.parameters.invalidName
          msg := sprintf("The name %v is not allowed", [input.parameters.invalidName])
        }

制約の例

policy-violation という名前のすべてのリソースを拒否するように実装できる例を次に示します。

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDenyName
metadata:
  name: no-policy-violation
spec:
  parameters:
    invalidName: "policy-violation"

制約テンプレートの各部

制約テンプレートには 2 つの重要な要素があります。

  • ユーザーに作成してもらう制約のスキーマ。制約テンプレートのスキーマは、crd フィールドに格納されます。

  • 制約の評価時に実行される Rego ソースコード。テンプレートの Rego ソースコードは targets フィールドに格納されます。

スキーマ(crd フィールド)

CRD フィールドは、Kubernetes API サーバー用の制約リソースを定義する Kubernetes カスタム リソース定義を作成するための設計図です。次のフィールドにデータを入力するだけで十分です。

フィールド 説明
spec.crd.spec.names.kind 制約の種類。小文字の場合、このフィールドの値は metadata.name と等しくなければなりません。
spec.crd.spec.validation.openAPIV3Schema

制約リソースの spec.parameters フィールドのスキーマ(これ以外の制約のスキーマは Policy Controller によって自動的に定義されます)。通常の CRD リソースの場合と同じ規則に従います。

制約テンプレートの名前の先頭に K8s を付加すると、Google Cloud リソースを対象とする Forseti テンプレートなど、他の種類の制約テンプレートとの競合を回避できます。

Rego ソースコード(targets フィールド)

以降のセクションでは、Rego のソースコードについてさらに詳しく説明します。

場所

Rego ソースコードは spec.targets フィールドに保存されます。ここで targets は、次の形式のオブジェクトの配列です。

{"target": "admission.k8s.gatekeeper.sh","rego": REGO_SOURCE_CODE, "libs": LIST_OF_REGO_LIBRARIES}
  • target: Policy Controller に、確認対象のシステム(この場合は Kubernetes)について指示します。ただし、許可される targets のエントリは 1 つのみです。
  • rego: 制約のソースコードです。
  • libs: 制約テンプレートで使用できる Rego コードのライブラリのオプション リストです。これは、共有ライブラリの使用を容易にすることを目的としたものであり、このドキュメントの対象外です。

ソースコード

上記の制約となる Rego のソースコードを次に示します。

package k8sdenynames

violation[{"msg": msg}] {
   input.review.object.metadata.name == input.parameters.invalidName
   msg := sprintf("The name %v is not allowed", [input.parameters.invalidName])
}

次の点にご注意ください。

  • OPA(Rego のランタイム)には package k8sdenynames が必要です。値は無視されます。
  • 違反があるかどうかを確認するために Policy Controller が呼び出す Rego ルールは violation と呼ばれます。このルールに一致する場合、制約の違反が発生しています。
  • violation ルールにはシグネチャ violation[{"msg": "violation message for the user"}] があります。ここで、"msg" の値はユーザーに返される違反メッセージです。
  • 制約に提供されたパラメータは、キーワード input.parameters の下で使用できるようになります。
  • request-under-test はキーワード input.review に保存されます。

キーワード input.review には次のフィールドがあります。

フィールド 説明
uid この特定のリクエストの一意の ID であり、監査中は使用できません。
kind

object-under-test の種類の情報。次の形式となります。

  • kind: リソースの種類
  • group: リソース グループ
  • version: リソース バージョン
name リソース名。ユーザーが API サーバーに依存して CREATE リクエストで名前を生成している場合は、空になることがあります。
namespace リソースの名前空間(クラスタ スコープのリソースには提供されません)。
operation リクエストされたオペレーション(CREATE や UPDATE など)。監査中は使用できません。
userInfo

リクエストを行っているユーザーの情報。監査中は使用できません。次の形式となります。

  • username: リクエストを行っているユーザー
  • uid: ユーザーの UID
  • groups: ユーザーがメンバーとして所属するグループのリスト
  • extra: Kubernetes によって提供される追加のユーザー情報
object ユーザーが変更または作成しようとしているオブジェクト。
oldObject オブジェクトの元の状態。UPDATE オペレーションでのみ使用できます。
dryRun このリクエストが kubectl --dry-run で呼び出されたかどうか。監査では使用できません。

参照制約テンプレートの作成

参照制約テンプレートは、ユーザーが 1 つのオブジェクトを他のオブジェクトに対して制約できるようにするテンプレートです。一例として「一致する Ingress が存在することが判明するまで Pod の作成を許可しない」というものが考えられます。別の例では、「2 つのサービスに同じホスト名を許可しない」があります。

Policy Controller を使用すると、ユーザーが提供するリソースのセットについて API サーバーを監視することにより、参照制約を作成できます。リソースが変更されると、Policy Controller によりローカルでそれがキャッシュに保存されるので、Rego ソースコードから簡単に参照できるようなります。Policy Controller は、このキャッシュを data.inventory キーワードで使用できるようにします。

クラスタ スコープのリソースは、次の場所のキャッシュに保存されます。

data.inventory.cluster["GROUP_VERSION"]["KIND"]["NAME"]

たとえば、my-favorite-node という名前のノードは次の場所で見つかります。

data.inventory.cluster["v1"]["Node"]["my-favorite-node"]

名前空間スコープのリソースは、次の場所のキャッシュに保存されます。

data.inventory.namespace["NAMESPACE"]["GROUP_VERSION"]["KIND"]["NAME"]

たとえば、名前空間 shipping-prodproduction-variables という名前の ConfigMap は、次の場所で見つかります。

data.inventory.namespace["shipping-prod"]["v1"]["ConfigMap"]["production-variables"]

オブジェクトの完全なコンテンツは、このキャッシュの場所に保存されます。これは Rego ソースコードで参照できますが、必要に応じて参照してください。

Rego の詳細

上の例では、Rego の Kubernetes リソースの制約を簡単に作成できるようにする Policy Controller の独自の機能について説明しました。Rego での制約の作成方法に関する完全なチュートリアルは、このガイドの対象外です。ただし、Rego 言語自体の構文と機能については、Open Policy Agent のドキュメントをご覧ください。

制約テンプレートのインストール

制約テンプレートを作成したら、kubectl apply を使用してテンプレートを適用します。これにより、Policy Controller が取り込み処理を行います。制約テンプレートをインスタンス化する際に、制約テンプレートの status フィールドにエラーがないことを確認してください。正常に取り込むと、status フィールドに created: true が表示され、status フィールドに記載されている observedGenerationmetadata.generation フィールドと等しくなります。

テンプレートが取り込まれたら、制約の作成で説明されているように、テンプレートに制約を適用できます。

制約テンプレートの削除

制約テンプレートを削除する手順は次のとおりです。

  1. 保持する必要がある制約が制約テンプレートを使用していないことを確認します。

    kubectl get TEMPLATE_NAME
    

    制約テンプレートの名前とクラスタ内の別のオブジェクトの間で名前の競合がある場合は、代わりに次のコマンドを使用します。

    kubectl get TEMPLATE_NAME.constraints.gatekeeper.sh
    
  2. 制約テンプレートを削除します。

    kubectl delete constrainttemplate CONSTRAINT_TEMPLATE_NAME
    

制約テンプレートを削除すると、そのテンプレートを参照する制約を作成できなくなります。

次のステップ