このページでは、事前作成された制約テンプレートがニーズに合わない場合にカスタム制約テンプレートを作成し、Policy Controller を拡張する方法について説明します。
このページは、監査または適用のために自動化や、宣言型構成のテンプレート化により、クラウド プラットフォーム内で実行されているすべてのリソースが組織のコンプライアンス要件を確実に満たすようにする IT 管理者とオペレーターを対象としています。Google Cloud のコンテンツで参照する一般的なロールとタスク例の詳細については、一般的な GKE Enterprise ユーザーロールとタスクをご覧ください。
Policy Controller のポリシーは、OPA Constraint Framework を使用して記述され、Rego で作成されています。ポリシーは、Kubernetes オブジェクトのすべてのフィールドを評価できます。
Rego を使用したポリシーの作成は特殊なスキルです。このため、共通の制約テンプレートのライブラリがデフォルトでインストールされます。制約の作成時にこれらの制約テンプレートを呼び出すことができます。特殊なニーズがある場合は、独自の制約テンプレートを作成できます。
制約テンプレートを使用すると、ポリシーのロジックを特定の要件から分離して、再利用や委任を行うことができます。制約の作成は、オープンソース プロジェクト、ソフトウェア ベンダー、規制の専門家など、サードパーティが開発した制約テンプレートを使用して行えます。
始める前に
- Policy Controller をインストールします。
制約テンプレートの例
以下は、制約の作成者が指定した値と名前が一致するすべてのリソースを拒否する制約テンプレートの例です。このページの残りの部分では、テンプレートの内容について説明します。その過程で、重要なコンセプトについてハイライト表示します。
階層リポジトリで 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 |
制約リソースの |
制約テンプレートの名前の先頭に 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 |
|
name |
リソース名。ユーザーが API サーバーに依存して CREATE リクエストで名前を生成している場合は、空になることがあります。 |
namespace |
リソースの名前空間(クラスタ スコープのリソースには提供されません)。 |
operation |
リクエストされたオペレーション(CREATE や UPDATE など)。監査中は使用できません。 |
userInfo |
リクエストを行っているユーザーの情報。監査中は使用できません。次の形式となります。
|
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-prod
の production-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
フィールドに記載されている observedGeneration
が metadata.generation
フィールドと等しくなります。
テンプレートが取り込まれたら、制約の作成で説明されているように、テンプレートに制約を適用できます。
制約テンプレートの削除
制約テンプレートを削除する手順は次のとおりです。
保持する必要がある制約が制約テンプレートを使用していないことを確認します。
kubectl get TEMPLATE_NAME
制約テンプレートの名前とクラスタ内の別のオブジェクトの間で名前の競合がある場合は、代わりに次のコマンドを使用します。
kubectl get TEMPLATE_NAME.constraints.gatekeeper.sh
制約テンプレートを削除します。
kubectl delete constrainttemplate CONSTRAINT_TEMPLATE_NAME
制約テンプレートを削除すると、そのテンプレートを参照する制約を作成できなくなります。
次のステップ
- Policy Controller の詳細を確認する。
- 制約テンプレート ライブラリのリファレンス ドキュメントを参照する。
- PodSecurityPolicies の代わりに制約を使用する方法を学習する。