ポリシーを遵守した Google Cloud リソースの作成


このチュートリアルでは、プラットフォーム管理者が Policy Controller ポリシーを使用して、Config Connector で Google Cloud リソースの作成方法を管理する方法について説明します。

このチュートリアルの手順は、Kubernetes または Google Kubernetes Engine(GKE)に関する基本的な知識があることを前提としています。このチュートリアルでは、Cloud Storage バケットに対して許可されるロケーションを制限するポリシーを定義します。

Policy Controller は、セキュリティ、規制、ビジネスルールに関連するポリシーを使用して Kubernetes クラスタ リソースのコンプライアンスを確認、監査、適用します。Policy Controller は、OPA Gatekeeper オープンソース プロジェクトからビルドされています。

Config Connector は、Google Cloud リソースのライフサイクルを Kubernetes カスタム リソースとして記述することで、そのライフサイクルを作成、管理します。Google Cloud リソースを作成するには、Config Connector が管理する Namespace に Kubernetes リソースを作成します。次の例では、Config Connector を使用して Cloud Storage バケットを記述する方法を示します。

apiVersion: storage.cnrm.cloud.google.com/v1beta1
kind: StorageBucket
metadata:
  name: my-bucket
spec:
  location: us-east1

Config Connector を使用して Google Cloud リソースを管理することで、Google Kubernetes Engine(GKE)Enterprise エディションのクラスタでリソースを作成する際に、Policy Controller ポリシーを適用できます。これらのポリシーにより、ポリシーに違反する方法でリソースを作成または変更するアクションを防止または報告できます。たとえば、Cloud Storage バケットのロケーションを制限するポリシーを適用できます。

Kubernetes リソースモデル(KRM)に基づくこのアプローチにより、一貫性のあるツールとワークフローを使用して、Kubernetes リソースと Google Cloud リソースの両方を管理できます。このチュートリアルでは、次のタスクを行う方法について説明します。

  • Google Cloud リソースを管理するポリシーを定義します。
  • デベロッパーと管理者がポリシーに違反する Google Cloud リソースの作成を防ぐコントロールを実装します。
  • Config Connector の外部でリソースを作成した場合でも、既存の Google Cloud リソースをポリシーに対して監査するコントロールを実装します。
  • リソース定義を作成、更新する場合に、デベロッパーや管理者に迅速なフィードバックを提供します。
  • Kubernetes クラスタに定義を適用する前に、ポリシーに対して Google Cloud リソース定義を検証します。

目標

  • Config Connector アドオンを含む Google Kubernetes Engine(GKE)Enterprise エディション クラスタを作成します。
  • Policy Controller をインストールします。
  • Cloud Storage バケットの許可されるロケーションを制限するポリシーを作成します。
  • ポリシーによって、許可されていないロケーションには Cloud Storage バケットが作成できないことを確認します。
  • 開発中に Cloud Storage バケット定義のポリシー コンプライアンスを評価します。
  • ポリシー コンプライアンス用の既存の Cloud Storage バケットを監査します。

費用

このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

準備

  1. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  2. Google Cloud プロジェクトで課金が有効になっていることを確認します

  3. Google Cloud コンソールで、「Cloud Shell をアクティブにする」をクリックします。

    Cloud Shell をアクティブにする

  4. Cloud Shell で、このチュートリアルで使用する Google Cloud プロジェクトを設定します。

    gcloud config set project PROJECT_ID
    

    PROJECT_ID は、プロジェクトの Google Cloud プロジェクト ID に置き換えます。このコマンドを実行すると、Cloud Shell は、プロジェクト ID を含むエクスポートされた GOOGLE_CLOUD_PROJECT という環境変数を作成します。Cloud Shell を使用しない場合は、次のコマンドを使用して環境変数を作成できます。

    export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value core/project)
    
  5. GKE API を有効にします。

    gcloud services enable container.googleapis.com
    
  6. このチュートリアル用に作成されたファイルを保存するディレクトリを作成します。

    mkdir -p ~/cnrm-gatekeeper-tutorial
    
  7. 作成したディレクトリに移動します。

    cd ~/cnrm-gatekeeper-tutorial
    

GKE クラスタを作成する

  1. Cloud Shell で、Config Connector アドオンWorkload Identity がある GKE クラスタを作成します。

    gcloud container clusters create CLUSTER_NAME \
      --addons ConfigConnector \
      --enable-ip-alias \
      --num-nodes 4 \
      --release-channel regular \
      --scopes cloud-platform \
      --workload-pool $GOOGLE_CLOUD_PROJECT.svc.id.goog \
      --zone ZONE
    

    次のように置き換えます。

    • CLUSTER_NAME: このプロジェクトに使用するクラスタの名前(例: cnrm-gatekeeper-tutorial)。
    • ZONE: ご利用のロケーションに近い Compute Engine ゾーン(例: asia-southeast1-b)。

    Config Connector アドオンは、GKE クラスタの Google Cloud リソースカスタム リソース定義(CRD)をインストールします。

  2. 省略可: 環境で限定公開クラスタを使用する場合は、GKE クラスタ コントロール プレーンが Policy Controller Webhook に接続できるようにファイアウォール ルールを追加します。

    gcloud compute firewall-rules create allow-cluster-control-plane-tcp-8443 \
      --allow tcp:8443 \
      --network default \
      --source-ranges CONTROL_PLANE_CIDR \
      --target-tags NODE_TAG
    

    次のように置き換えます。

    • CONTROL_PLANE_CIDR: GKE クラスタ コントロール プレーンの IP 範囲(例: 172.16.0.16/28)。
    • NODE_TAG: GKE クラスタ内のすべてのノードに適用されるタグ。

    このオプションのファイアウォール ルールは、クラスタがプライベート ノードを使用するときに Policy Controller Webhook が機能するために必要です。

Config Connector を設定する

Config Connector をインストールする Google Cloud プロジェクトは、ホスト プロジェクトと呼ばれます。Config Connector を使用してリソースを管理するプロジェクトは、マネージド プロジェクトと呼ばれます。このチュートリアルでは、Config Connector を使用して GKE クラスタと同じプロジェクトに Google Cloud リソースを作成します。これにより、ホスト プロジェクトとマネージド プロジェクトが同じプロジェクトになります。

  1. Cloud Shell で、Config Connector 用の Google サービス アカウントを作成します。

    gcloud iam service-accounts create SERVICE_ACCOUNT_NAME \
      --display-name "Config Connector Gatekeeper tutorial"
    

    SERVICE_ACCOUNT_NAME は、サービス アカウントに使用する名前(cnrm-gatekeeper-tutorial など)に置き換えます。Config Connector は、この Google サービス アカウントを使用して、マネージド プロジェクトにリソースを作成します。

  2. Google サービス アカウントにストレージ管理者ロールを付与します。

    gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
      --member "serviceAccount:SERVICE_ACCOUNT_NAME@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com" \
      --role roles/storage.admin
    

    このチュートリアルでは、Config Connector を使用して Cloud Storage バケットを作成するため、ストレージ管理者ロールを使用します。実際の環境では、Config Connector 用に作成する Google Cloud リソースの管理に必要なロールを付与します。事前定義ロールの詳細については、IAM ドキュメントのロールについてをご覧ください。

  3. このチュートリアルで作成する Config Connector リソースの Kubernetes Namespace を作成します。

    kubectl create namespace NAMESPACE
    

    NAMESPACE は、チュートリアルで使用する Kubernetes Namespace(tutorial など)に置き換えます。

  4. Namespace にアノテーションを付けて、Config Connector が Google Cloud リソース(マネージド プロジェクト)の作成に使用するプロジェクトを指定します。

    kubectl annotate namespace NAMESPACE \
        cnrm.cloud.google.com/project-id=$GOOGLE_CLOUD_PROJECT
    
  5. Kubernetes Namespace の Config Connector を有効にする ConfigConnectorContext リソースを作成して、作成した Google サービス アカウントに関連付けます。

    cat << EOF | kubectl apply -f -
    apiVersion: core.cnrm.cloud.google.com/v1beta1
    kind: ConfigConnectorContext
    metadata:
      name: configconnectorcontext.core.cnrm.cloud.google.com
      namespace: NAMESPACE
    spec:
      googleServiceAccount: SERVICE_ACCOUNT_NAME@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com
    EOF
    

    ConfigConnectorContext リソースを作成すると、Config Connector は Namespace 内の Config Connector リソースを管理する cnrm-system Namespace に Kubernetes サービス アカウントStatefulSet を作成します。

  6. Namespace の Config Connector コントローラ Pod が使用可能になるまで待ちます。

    kubectl wait --namespace cnrm-system --for=condition=Ready pod \
      -l cnrm.cloud.google.com/component=cnrm-controller-manager,cnrm.cloud.google.com/scoped-namespace=NAMESPACE
    

    Pod の準備ができると、Cloud Shell プロンプトが表示されます。error: no matching resources found メッセージが表示された場合は、しばらく待ってから再試行してください。

  7. IAM ポリシー バインディングを作成することによって、Config Connector Kubernetes サービス アカウントを Google サービス アカウントにバインドします。

    gcloud iam service-accounts add-iam-policy-binding \
      SERVICE_ACCOUNT_NAME@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \
      --member "serviceAccount:$GOOGLE_CLOUD_PROJECT.svc.id.goog[cnrm-system/cnrm-controller-manager-NAMESPACE]" \
      --role roles/iam.workloadIdentityUser
    

    このバインドにより、cnrm-system Namespace 内の cnrm-controller-manager-NAMESPACE Kubernetes Service アカウントが、作成した Google サービス アカウントとして機能できるようになります。

Policy Controller をインストールする

インストールの手順に沿って Policy Controller をインストールします。

監査間隔は 60 秒にします。

Config Connector を使用して Google Cloud リソースを作成する

  1. Cloud Shell で、us-central1 リージョンの Cloud Storage バケットを表す Config Connector マニフェストを作成します。

    cat << EOF > tutorial-storagebucket-us-central1.yaml
    apiVersion: storage.cnrm.cloud.google.com/v1beta1
    kind: StorageBucket
    metadata:
      name: tutorial-us-central1-$GOOGLE_CLOUD_PROJECT
      namespace: NAMESPACE
    spec:
      location: us-central1
      uniformBucketLevelAccess: true
    EOF
    
  2. Cloud Storage バケットを作成するには、マニフェストを適用します。

    kubectl apply -f tutorial-storagebucket-us-central1.yaml
    
  3. Config Connector によって Cloud Storage バケットが作成されたことを確認します。

    gsutil ls | grep tutorial
    

    出力は次のようになります。

    gs://tutorial-us-central1-PROJECT_ID/
    

    この出力には、Google Cloud プロジェクト ID である PROJECT_ID が含まれます。

    この出力が表示されない場合は、少し待ってから、この確認手順をもう一度繰り返します。

ポリシーを作成する

Policy Controller のポリシーは、制約テンプレート制約から構成されます。制約テンプレートには、ポリシーのロジックが含まれています。制約では、ポリシーが適用される場所と、ポリシー ロジックへの入力パラメータが指定されます。

  1. Cloud Shell で、Cloud Storage バケットのロケーションを制限する制約テンプレートを作成します。

    cat << EOF > tutorial-storagebucket-location-template.yaml
    apiVersion: templates.gatekeeper.sh/v1beta1
    kind: ConstraintTemplate
    metadata:
      name: gcpstoragelocationconstraintv1
    spec:
      crd:
        spec:
          names:
            kind: GCPStorageLocationConstraintV1
          validation:
            openAPIV3Schema:
              properties:
                locations:
                  type: array
                  items:
                    type: string
                exemptions:
                  type: array
                  items:
                    type: string
      targets:
      - target: admission.k8s.gatekeeper.sh
        rego: |
          package gcpstoragelocationconstraintv1
    
          allowedLocation(reviewLocation) {
              locations := input.parameters.locations
              satisfied := [ good | location = locations[_]
                                    good = lower(location) == lower(reviewLocation)]
              any(satisfied)
          }
    
          exempt(reviewName) {
              input.parameters.exemptions[_] == reviewName
          }
    
          violation[{"msg": msg}] {
              bucketName := input.review.object.metadata.name
              bucketLocation := input.review.object.spec.location
              not allowedLocation(bucketLocation)
              not exempt(bucketName)
              msg := sprintf("Cloud Storage bucket <%v> uses a disallowed location <%v>, allowed locations are %v", [bucketName, bucketLocation, input.parameters.locations])
          }
    
          violation[{"msg": msg}] {
              not input.parameters.locations
              bucketName := input.review.object.metadata.name
              msg := sprintf("No permitted locations provided in constraint for Cloud Storage bucket <%v>", [bucketName])
          }
    EOF
    
  2. テンプレートを適用して Cloud Storage バケットを作成します。

    kubectl apply -f tutorial-storagebucket-location-template.yaml
    
  3. シンガポールとジャカルタのリージョン(asia-southeast1asia-southeast2)にあるバケットのみを許可する制約を作成します。この制約は、前の手順で作成した Namespace に適用されます。Cloud Build のデフォルトの Cloud Storage バケットは制約の対象から除外されます。

    cat << EOF > tutorial-storagebucket-location-constraint.yaml
    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: GCPStorageLocationConstraintV1
    metadata:
      name: singapore-and-jakarta-only
    spec:
      enforcementAction: deny
      match:
        kinds:
        - apiGroups:
          - storage.cnrm.cloud.google.com
          kinds:
          - StorageBucket
        namespaces:
        - NAMESPACE
      parameters:
        locations:
        - asia-southeast1
        - asia-southeast2
        exemptions:
        - ${GOOGLE_CLOUD_PROJECT}_cloudbuild
    EOF
    
  4. バケットが存在しているゾーンを制限するには、制約を適用します。

    kubectl apply -f tutorial-storagebucket-location-constraint.yaml
    

ポリシーを確認する

  1. 許可されていないロケーション(us-west1)内の Cloud Storage バケットを表すマニフェストを作成します。

    cat << EOF > tutorial-storagebucket-us-west1.yaml
    apiVersion: storage.cnrm.cloud.google.com/v1beta1
    kind: StorageBucket
    metadata:
      name: tutorial-us-west1-$GOOGLE_CLOUD_PROJECT
      namespace: NAMESPACE
    spec:
      location: us-west1
      uniformBucketLevelAccess: true
    EOF
    
  2. Cloud Storage バケットを作成するには、マニフェストを適用します。

    kubectl apply -f tutorial-storagebucket-us-west1.yaml
    

    出力は次のようになります。

    Error from server ([singapore-and-jakarta-only] Cloud Storage bucket
    <tutorial-us-west1-PROJECT_ID> uses a disallowed location
    <us-west1>, allowed locations are ["asia-southeast1",
    "asia-southeast2"]): error when creating
    "tutorial-storagebucket-us-west1.yaml": admission webhook
    "validation.gatekeeper.sh" denied the request: [singapore-and-jakarta-only]
    Cloud Storage bucket <tutorial-us-west1-PROJECT_ID> uses a
    disallowed location <us-west1>, allowed locations are
    ["asia-southeast1", "asia-southeast2"]
    
  3. 省略可: リクエストを拒否する判定の記録は、Cloud Audit Logs で確認できます。プロジェクトに対する管理アクティビティ ログをクエリします。

    gcloud logging read --limit=1 \
        "logName=\"projects/$GOOGLE_CLOUD_PROJECT/logs/cloudaudit.googleapis.com%2Factivity\""'
        resource.type="k8s_cluster"
        resource.labels.cluster_name="CLUSTER_NAME"
        resource.labels.location="ZONE"
        protoPayload.authenticationInfo.principalEmail!~"system:serviceaccount:cnrm-system:.*"
        protoPayload.methodName:"com.google.cloud.cnrm."
        protoPayload.status.code=7'
    

    出力は次のようになります。

    insertId: 3c6940bb-de14-4d18-ac4d-9a6becc70828
    labels:
      authorization.k8s.io/decision: allow
      authorization.k8s.io/reason: ''
      mutation.webhook.admission.k8s.io/round_0_index_0: '{"configuration":"mutating-webhook.cnrm.cloud.google.com","webhook":"container-annotation-handler.cnrm.cloud.google.com","mutated":true}'
      mutation.webhook.admission.k8s.io/round_0_index_1: '{"configuration":"mutating-webhook.cnrm.cloud.google.com","webhook":"management-conflict-annotation-defaulter.cnrm.cloud.google.com","mutated":true}'
    logName: projects/PROJECT_ID/logs/cloudaudit.googleapis.com%2Factivity
    operation:
      first: true
      id: 3c6940bb-de14-4d18-ac4d-9a6becc70828
      last: true
      producer: k8s.io
    protoPayload:
      '@type': type.googleapis.com/google.cloud.audit.AuditLog
      authenticationInfo:
        principalEmail: user@example.com
      authorizationInfo:
      - permission: com.google.cloud.cnrm.storage.v1beta1.storagebuckets.create
        resource: storage.cnrm.cloud.google.com/v1beta1/namespaces/NAMESPACE/storagebuckets/tutorial-us-west1-PROJECT_ID
      methodName: com.google.cloud.cnrm.storage.v1beta1.storagebuckets.create
      requestMetadata:
        callerIp: 203.0.113.1
        callerSuppliedUserAgent: kubectl/v1.21.1 (linux/amd64) kubernetes/5e58841
      resourceName: storage.cnrm.cloud.google.com/v1beta1/namespaces/NAMESPACE/storagebuckets/tutorial-us-west1-PROJECT_ID
      serviceName: k8s.io
      status:
        code: 7
        message: Forbidden
    receiveTimestamp: '2021-05-21T06:56:24.940264678Z'
    resource:
      labels:
        cluster_name: CLUSTER_NAME
        location: CLUSTER_ZONE
        project_id: PROJECT_ID
      type: k8s_cluster
    timestamp: '2021-05-21T06:56:09.060635Z'
    

    methodName フィールドには、試行されたオペレーションが示されます。resourceName には Config Connector リソースのフルネームが示されます。status セクションには、リクエストの失敗がエラーコード 7 と「Forbidden」というメッセージで示されます。

  4. 許可されたロケーション(asia-southeast1)内の Cloud Storage バケットを表すマニフェストを作成します。

    cat << EOF > tutorial-storagebucket-asia-southeast1.yaml
    apiVersion: storage.cnrm.cloud.google.com/v1beta1
    kind: StorageBucket
    metadata:
      name: tutorial-asia-southeast1-$GOOGLE_CLOUD_PROJECT
      namespace: NAMESPACE
    spec:
      location: asia-southeast1
      uniformBucketLevelAccess: true
    EOF
    
  5. Cloud Storage バケットを作成するには、マニフェストを適用します。

    kubectl apply -f tutorial-storagebucket-asia-southeast1.yaml
    

    出力は次のようになります。

    storagebucket.storage.cnrm.cloud.google.com/tutorial-asia-southeast1-PROJECT_ID created
    

    この出力には、Google Cloud プロジェクト ID である PROJECT_ID が含まれます。

  6. Config Connector によって Cloud Storage バケットが作成されたことを確認します。

    gsutil ls | grep tutorial
    

    出力は次のようになります。

    gs://tutorial-asia-southeast1-PROJECT_ID/
    gs://tutorial-us-central1-PROJECT_ID/
    

    この出力が表示されない場合は、少し待ってから、この確認手順をもう一度繰り返します。

監査の制約

Policy Controller の監査コントローラは、制約と比較してリソースを定期的に評価します。コントローラは、制約の前に作成されたリソースのポリシー違反と、Config Connector の外部で作成されたリソースのポリシー違反を検出します。

  1. Cloud Shell で、GCPStorageLocationConstraintV1 制約テンプレートを使用するすべての制約について違反を表示します。

    kubectl get gcpstoragelocationconstraintv1 -o json \
      | jq '.items[].status.violations'
    

    出力は次のようになります。

    [
      {
        "enforcementAction": "deny",
        "kind": "StorageBucket",
        "message": "Cloud Storage bucket <tutorial-us-central1-PROJECT_ID>
        uses a disallowed location <us-central1>, allowed locations are
        \"asia-southeast1\", \"asia-southeast2\"",
        "name": "tutorial-us-central1-PROJECT_ID",
        "namespace": "NAMESPACE"
      }
    ]
    

    制約を作成する前に、us-central1 に作成した Cloud Storage バケットが表示されます。

開発中にリソースを検証する

開発および継続的インテグレーションでのビルドの際には、リソースを制約に対して検証してから、GKE クラスタに適用すると効果的です。検証によって迅速なフィードバックが得られ、リソースや制約の問題を早期に発見できます。次の手順では、kpt を使用してリソースを検証する方法を示します。kpt コマンドライン ツールを使用すると、Kubernetes リソース マニフェストを管理、適用できます。

  1. Cloud Shell で、kpt を使用して gatekeeper KRM 関数を実行します。

    kpt fn eval . --image=gcr.io/kpt-fn/gatekeeper:v0.2 --truncate-output=false
    

    KRM 関数は、ローカル ファイル システムに格納された Kubernetes リソースを YAML ファイルとして変換または検証できるプログラムです。gatekeeper KRM 関数は、Gatekeeper ポリシーに対して Config Connector の Cloud Storage バケット リソースを検証します。gatekeeper KRM 関数は、Artifact Registry で利用可能なコンテナ イメージとしてパッケージ化されています。

    この関数により、us-central1 リージョンと us-west1 リージョンの Cloud Storage バケットのマニフェスト ファイルが制約に違反していることが報告されます。

    出力は次のようになります。

    [RUNNING] "gcr.io/kpt-fn/gatekeeper:v0.2"
    [FAIL] "gcr.io/kpt-fn/gatekeeper:v0.2"
      Results:
        [ERROR] Cloud Storage bucket <tutorial-us-central1-PROJECT_ID> uses a disallowed location <us-central1>, allowed locations are ["asia-southeast1", "asia-southeast2"] violatedConstraint: singapore-and-jakarta-only in object "storage.cnrm.cloud.google.com/v1beta1/StorageBucket/tutorial/tutorial-us-central1-GOOGLE_CLOUD_PROJECT" in file "tutorial-storagebucket-us-central1.yaml"
        [ERROR] Cloud Storage bucket <tutorial-us-west1-PROJECT_ID> uses a disallowed location <us-west1>, allowed locations are ["asia-southeast1", "asia-southeast2"] violatedConstraint: singapore-and-jakarta-only in object "storage.cnrm.cloud.google.com/v1beta1/StorageBucket/tutorial/tutorial-us-west1-GOOGLE_CLOUD_PROJECT" in file "tutorial-storagebucket-us-west1.yaml"
      Stderr:
        "[error] storage.cnrm.cloud.google.com/v1beta1/StorageBucket/test/tutorial-us-central1-PROJECT_ID : Cloud Storage bucket <tutorial-us-central1-PROJECT_ID> uses a disallowed location <us-central1>, allowed locations are [\"asia-southeast1\", \"asia-southeast2\"]"
        "violatedConstraint: singapore-and-jakarta-only"
        ""
        "[error] storage.cnrm.cloud.google.com/v1beta1/StorageBucket/test/tutorial-us-west1-PROJECT_IDT : Cloud Storage bucket <tutorial-us-west1-PROJECT_IDgt; uses a disallowed location <us-west1>, allowed locations are [\"asia-southeast1\", \"asia-southeast2\"]"
        "violatedConstraint: singapore-and-jakarta-only"
        ""
      Exit code: 1
    

Config Connector 外で作成されたリソースを検証する

Google Cloud リソースをエクスポートすることで、Config Connector の外部で作成された Google Cloud リソースを検証できます。リソースをエクスポートしたら、次のいずれかの方法で、エクスポートされたリソースに対して Policy Controller ポリシーを評価します。

  • gatekeeper KRM 関数を使用してリソースを検証する。

  • Config Connector にリソースをインポートする。

リソースをエクスポートするには、Cloud Asset Inventory を使用します

  1. Cloud Shell で、Cloud Asset API を有効にします。

    gcloud services enable cloudasset.googleapis.com
    
  2. us-central1us-west1 にある Cloud Storage バケットの Kubernetes リソース マニフェスト ファイルを削除します。

    rm tutorial-storagebucket-us-*.yaml
    
  3. 現在のプロジェクトにある Cloud Storage リソースをすべてエクスポートし、その出力を export.yaml というファイルに保存します。

    gcloud beta resource-config bulk-export \
      --project $GOOGLE_CLOUD_PROJECT \
      --resource-format krm \
      --resource-types StorageBucket > export.yaml
    

    出力は次のようになります。

    Exporting resource configurations to stdout...
    
    Export complete.
    
  4. KRM 関数をつなげて kpt パイプラインを作成します。このパイプラインでは、現在のディレクトリ内のリソースが Cloud Storage バケットのロケーション ポリシーに対して検証されます。

    kpt fn source . \
      | kpt fn eval - --image=gcr.io/kpt-fn/set-namespace:v0.1 -- namespace=NAMESPACE \
      | kpt fn eval - --image=gcr.io/kpt-fn/gatekeeper:v0.2 --truncate-output=false
    

    エクスポートされたリソースには、namespace メタデータ属性の値がありません。このパイプラインは、set-namespace という KRM 関数を使用して、すべてのリソースの namespace 値を設定します。

    出力は次のようになります。エクスポートしたリソースの違反が表示されます。

    [RUNNING] "gcr.io/kpt-fn/set-namespace:v0.1"
    [PASS] "gcr.io/kpt-fn/set-namespace:v0.1"
    [RUNNING] "gcr.io/kpt-fn/gatekeeper:v0.2"
    [FAIL] "gcr.io/kpt-fn/gatekeeper:v0.2"
      Results:
        [ERROR] Cloud Storage bucket <tutorial-us-central1-PROJECT_ID> uses a disallowed location <us-central1>, allowed locations are ["asia-southeast1", "asia-southeast2"] violatedConstraint: singapore-and-jakarta-only in object "storage.cnrm.cloud.google.com/v1beta1/StorageBucket/tutorial/tutorial-us-central1-GOOGLE_CLOUD_PROJECT" in file "export.yaml"
      Stderr:
        "[error] storage.cnrm.cloud.google.com/v1beta1/StorageBucket/test/tutorial-us-central1-PROJECT_ID : Cloud Storage bucket <tutorial-us-central1-PROJECT_ID> uses a disallowed location <us-central1>, allowed locations are [\"asia-southeast1\", \"asia-southeast2\"]"
        "violatedConstraint: singapore-and-jakarta-only"
        ""
      Exit code: 1
    

    Google Cloud プロジェクトに、このチュートリアルで扱う前に作成した Cloud Storage バケットが含まれていて、そのロケーションが制約に違反している場合は、前に作成したバケットが出力に表示されます。

以上で、Cloud Storage バケットの許可されたロケーションを管理するポリシーが正常に設定されました。チュートリアルはこれで終了です。他の Google Cloud リソースに対しては、引き続き独自のポリシーを追加できます。

トラブルシューティング

Config Connector によって目的の Google Cloud リソースが作成されない場合は、Cloud Shell で次のコマンドを使用して、Config Connector コントローラ マネージャーのログを確認します。

kubectl logs --namespace cnrm-system --container manager \
  --selector cnrm.cloud.google.com/component=cnrm-controller-manager,cnrm.cloud.google.com/scoped-namespace=NAMESPACE

Policy Controller が正しくポリシーを適用しなかった場合は、次のコマンドを使用してコントローラ マネージャーのログを表示します。

kubectl logs deployment/gatekeeper-controller-manager \
  --namespace gatekeeper-system

Policy Controller が制約オブジェクトの status フィールドに違反を報告しない場合は、次のコマンドを使用して監査コントローラのログを表示します。

kubectl logs deployment/gatekeeper-audit --namespace gatekeeper-system

このチュートリアルで他の問題が発生した場合は、次のドキュメントを確認することをおすすめします。

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。

プロジェクトの削除

  1. Google Cloud コンソールで、[リソースの管理] ページに移動します。

    [リソースの管理] に移動

  2. 削除するプロジェクトが組織に関連付けられている場合は、[名前] 列の [組織] リストを展開します。
  3. プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
  4. ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。

リソースを削除する

このチュートリアルで使用した Google Cloud プロジェクトを残しておく場合は、個々のリソースを削除します。

  1. Cloud Shell で、Cloud Storage バケットのロケーションの制約を削除します。

    kubectl delete -f tutorial-storagebucket-location-constraint.yaml
    
  2. Config Connector によって管理される Namespace 内のすべての storagebucket リソースに、文字列値 truecnrm.cloud.google.com/force-destroy アノテーションを追加します。

    kubectl annotate storagebucket --all --namespace NAMESPACE \
      cnrm.cloud.google.com/force-destroy=true
    

    このアノテーションは、バケットにオブジェクトが含まれている場合でも、GKE クラスタで対応する storagebucket リソースを削除する際に Config Connector が Cloud Storage バケットを削除できるようにするディレクティブです。

  3. Cloud Storage バケットを表す Config Connector リソースを削除します。

    kubectl delete --namespace NAMESPACE storagebucket --all
    
  4. GKE クラスタを削除します。

    gcloud container clusters delete CLUSTER_NAME \
      --zone ZONE --async --quiet
    
  5. IAM の Workload Identity ポリシー バインディングを削除します。

    gcloud iam service-accounts remove-iam-policy-binding \
      SERVICE_ACCOUNT_NAME@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \
      --member "serviceAccount:$GOOGLE_CLOUD_PROJECT.svc.id.goog[cnrm-system/cnrm-controller-manager-NAMESPACE]" \
      --role roles/iam.workloadIdentityUser
    
  6. Google サービス アカウントの Cloud Storage 管理者ロールのバインディングを削除します。

    gcloud projects remove-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
      --member "serviceAccount:SERVICE_ACCOUNT_NAME@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com" \
      --role roles/storage.admin
    
  7. Config Connector 用に作成した Google サービス アカウントを削除します。

    gcloud iam service-accounts delete --quiet \
      SERVICE_ACCOUNT_NAME@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com
    

次のステップ