Cloud Run for Anthos のクロス プロジェクト マルチテナンシー

このガイドでは、1 つ以上の Google Cloud プロジェクトから別の Google Cloud プロジェクト内の Google Kubernetes Engine クラスタで動作しているワークロードを実行し、管理できるように、Cloud Run for Anthos を構成する方法について説明します。

Cloud Run for Anthos でよく利用されている運用モデルは、アプリケーション デベロッパーがチームの Google Cloud プロジェクトから別のチームの Google Cloud プロジェクトの Google Kubernetes Engine クラスタにサービスをデプロイし、そのサービスを管理するモデルです。この機能(マルチテナンシー)により、プラットフォーム オペレータは組織内のさまざまな環境(本番環境、ステージング環境など)で実行されているサービスに対する開発チームのアクセスを調整できます。

Cloud Run for Anthos は特にエンタープライズ マルチテナンシーをサポートしています。このタイプのマルチテナンシーでは、クラスタ Google Cloud プロジェクトから Google Kubernetes Engine クラスタの特定のリソースにアクセスできるようになります。クラスタ Google Cloud プロジェクトへのアクセスが許可されている Google Cloud プロジェクトは、テナント Google Cloud プロジェクトです。クラスタ Google Cloud プロジェクトのテナントは、Cloud Run for Anthos を使用して、アクセス権が付与されているサービスやリソースに対するアクセス、運用、所有を行うことができます。

概念的には、Cloud Run for Anthos でエンタープライズ マルチテナンシーを構成するには、次の 4 つのステップがあります。

  1. Google グループと Identity and Access Management を使用して、クラスタ Google Cloud プロジェクトに対するテナント アクセスを構成します。
  2. 各テナント Google Cloud プロジェクトをクラスタ Google Cloud プロジェクトにマッピングする
  3. ログバケットとシンクを使用して、クラスタ Google Cloud プロジェクトのログデータをテナント Google Cloud プロジェクトに転送します。
  4. GKE のロールベースのアクセス制御を使用して、テナントのクラスタ権限を定義します。

始める前に

マルチテナンシーを構成するプラットフォーム オペレータは、次の要件を満たす必要があります。

ローカル環境変数を定義する

このプロセスで使用するコマンドを単純にするため、クラスタ Google Cloud プロジェクトとテナント Google Cloud プロジェクトの両方にローカル環境変数を定義します。

  1. YOUR_CLUSTER_PROJECT_ID をクラスタ Google Cloud プロジェクトの ID に置き換えて、次のコマンドを実行します。

    export CLUSTER_PROJECT_ID=YOUR_CLUSTER_PROJECT_ID
    
  2. YOUR_TENANT_PROJECT_ID をテナント Google Cloud プロジェクトの ID に置き換えて、次のコマンドを実行します。

    export TENANT_PROJECT_ID=$YOUR_TENANT_PROJECT_ID
    
  3. 次のコマンドを実行して、ローカル環境変数を確認します。

    echo "cluster Google Cloud project is:" $CLUSTER_PROJECT_ID
    echo "tenant Google Cloud project is:" $TENANT_PROJECT_ID
    

以降、$CLUSTER_PROJECT_ID$TENANT_PROJECT_ID が指定されているすべてのコマンドで、クラスタ Google Cloud プロジェクト ID とテナント Google Cloud プロジェクト ID が使用されます。

IAM 権限の確認

次の testIamPermissions コマンドを実行して、クラスタ Google Cloud プロジェクトとテナント Google Cloud プロジェクトのリソースにアクセスするために必要な IAM 権限があることを確認します。

次のコマンドを実行して、クラスタ Google Cloud プロジェクトの権限を確認します。

curl -X POST \
  -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
  --header "Content-Type: application/json" \
  --data '{"permissions":["logging.sinks.create", "logging.sinks.get", "resourcemanager.projects.setIamPolicy"]}' \
  https://cloudresourcemanager.googleapis.com/v1/projects/$CLUSTER_PROJECT_ID:testIamPermissions

クラスタ Google Cloud プロジェクトで想定される結果:

{
  "permissions": [
    "logging.sinks.create",
    "logging.sinks.get",
    "resourcemanager.projects.setIamPolicy"
  ]
}

各テナント Google Cloud プロジェクトに対する権限を確認するには、次のコマンドを実行します。

curl -X POST \
  -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
  --header "Content-Type: application/json" \
  --data '{"permissions":["logging.buckets.create", "logging.buckets.get", "resourcemanager.projects.setIamPolicy", "resourcesettings.settingvalues.create", "serviceusage.services.enable"]}' \
  https://cloudresourcemanager.googleapis.com/v1/projects/$TENANT_PROJECT_ID:testIamPermissions

各テナント Google Cloud プロジェクトで想定される結果:

{
  "permissions": [
    "logging.buckets.create",
    "logging.buckets.get",
    "resourcemanager.projects.setIamPolicy",
    "resourcesettings.settingvalues.create",
    "serviceusage.services.enable",
  ]
}

Google グループと Identity and Access Management を使用してテナント アクセスを構成する

Google グループを使用して、テナントに GKE クラスタへのアクセスを許可します。IAM 権限により、テナントには認証情報の取得が許可されますが、後のステップで Kubernetes ロールベースのアクセス制御を構成するまで、クラスタ内では何もできません。

テナント Google Cloud プロジェクトのすべてのユーザーを含む Google グループを作成する必要があります。セキュリティ グループの使用方法については、GKE 向け Google グループの使用をご覧ください。

Google グループに次のローカル環境変数を作成します。

export SECURITY_GROUP=gke-security-groups@company.com

Kubernetes クラスタ閲覧者

次のコマンドを実行して、テナントにクラスタの認証情報の取得を許可します。ただし、GKE クラスタ リソースの読み取りまたは操作は許可されません。

IAM リファレンス

gcloud projects add-iam-policy-binding $CLUSTER_PROJECT_ID \
   --member=group:$SECURITY_GROUP \
   --role='roles/container.clusterViewer' \
   --condition=None

特定のクラスタへのアクセスを制限するには、IAM 条件を使用します。

gcloud projects add-iam-policy-binding $CLUSTER_PROJECT_ID \
   --member=group:$SECURITY_GROUP \
   --role='roles/container.clusterViewer' \
   --condition="expression=resource.name == 'cluster-name',title=Restrict cluster access"

モニタリング閲覧者

次のコマンドを実行して、テナントにモニタリング指標の読み取りを許可します。

モニタリング ロールのリファレンス

gcloud projects add-iam-policy-binding $CLUSTER_PROJECT_ID \
   --member=group:$SECURITY_GROUP \
   --role='roles/monitoring.viewer' \
   --condition=None

各テナント Google Cloud プロジェクトをクラスタ Google Cloud プロジェクトにマッピングする

リソース設定値を使用して、テナント Google Cloud プロジェクトをクラスタ Google Cloud プロジェクトにマッピングします。

リソース設定は、個々のテナント Google Cloud プロジェクトに対して構成することも、フォルダ階層の任意のレベルで設定することもできます。単一テナント フォルダ レベルで設定するのが簡単ですが、テナント プロジェクト レベルごとに柔軟に設定することも可能です。設定後、テナントが Cloud Run for Anthos UI をブラウジングすると、クラスタ Google Cloud プロジェクトのサービスが表示されます。クラスタ Cloud プロジェクトまたは GKE クラスタの IAM 権限は変更されません。これは、テナント プロジェクト(またはフォルダ)からクラスタ Google Cloud プロジェクトへのマッピングにすぎません。

  1. テナント Google Cloud プロジェクトで resourcesettings API を有効にします。

    gcloud services enable resourcesettings.googleapis.com \
      --project=$TENANT_PROJECT_ID
    
  2. 次のコマンドを実行して、ユーザー ID に組織管理者の権限(roles/resourcesettings.admin)を追加します。

    gcloud organizations add-iam-policy-binding YOUR_ORGANIZATION_ID \
      --member=YOUR_ADMIN_MEMBER_ID \
      --role='roles/resourcesettings.admin'
    

    YOUR_ORGANIZATION_ID組織の ID に、YOUR_ADMIN_MEMBER_ID はユーザー ID(user:my-email@my-domain.com など)に置き換えます。

  3. 次のいずれかの方法でマッピングを定義します。

    すべての子 Google Cloud プロジェクトと Google Cloud フォルダで同じ値を使用する場合は、親 Google Cloud フォルダにリソース設定値を設定できます。

テナント プロジェクト

テナント Google Cloud プロジェクトごとにリソース設定値を設定します。

  1. テナント Google Cloud プロジェクトの name を取得し、ローカル環境変数に設定します。
    export TENANT_PROJECT_NUMBER=$(gcloud alpha projects describe $TENANT_PROJECT_ID --format="value(projectNumber)")
  2. リソース設定値ファイルを作成して、テナント Google Cloud プロジェクトからクラスタ Google loud プロジェクトへのマッピングを定義します。このファイルで複数のクラスタ Google Cloud プロジェクト ID を定義し、単一テナントの Google Cloud プロジェクトに追加できます。
    cat > value-file.json << EOF
    {
    "name": "projects/$TENANT_PROJECT_NUMBER/settings/cloudrun-multiTenancy/value",
    "value": {
      "stringSetValue": {
        "values": [ "projects/$CLUSTER_PROJECT_ID" ]
      }
    }
    }
    EOF
    
  3. リソース設定をテナント Google Cloud プロジェクトにデプロイします。
    gcloud alpha resource-settings set-value cloudrun-multiTenancy --value-file value-file.json --project $TENANT_PROJECT_ID

テナント フォルダ

親テナント プロジェクトにリソース設定値を設定し、その値をすべての子テナントの Google Cloud プロジェクトとフォルダに設定します。

  1. テナント フォルダの number を取得し、ローカル環境変数に設定します。
    export TENANT_FOLDER_NUMBER=$TENANT_FOLDER_NUMBER
    
  2. リソース設定値ファイルを作成して、テナント フォルダからクラスタ Google Cloud プロジェクトへのマッピングを定義します。このファイルに複数のクラスタ Google Cloud プロジェクト ID を定義し、1 つのテナント フォルダに追加できます。
    cat > value-file.json << EOF
    {
    "name": "folders/$TENANT_FOLDER_NUMBER/settings/cloudrun-multiTenancy/value",
    "value": {
      "stringSetValue": {
        "values": [ "projects/$CLUSTER_PROJECT_ID" ]
      }
    }
    }
    EOF
    
  3. リソース設定をテナント フォルダにデプロイします。
    gcloud alpha resource-settings set-value cloudrun-multiTenancy --value-file value-file.json --folder $TENANT_FOLDER_NUMBER

ログデータをルーティングするログバケットとシンクの設定

テナントごとにログバケットとシンクを作成します。また、クラスタ Google Cloud プロジェクトのログデータをテナント Google Cloud プロジェクトに転送するための権限を作成します。次の手順では、クラスタ Google Cloud プロジェクトの Namespace にあるすべてのログがバケットに転送されます。共有するログを制限する方法については、以下の設定をご覧ください。

次のローカル環境変数を作成します。

  • テナントがアクセスする GKE クラスタの Namespace を指定します。
  • シンクの名前。この手順を簡略化するため、前に作成したクラスタ Google Cloud プロジェクトとテナント Google Cloud プロジェクトのローカル環境変数の組み合わせを名前に使用します。この値は変更できます。
export NAMESPACE=$NAMESPACE
export SINK_NAME=$CLUSTER_PROJECT_ID-$TENANT_PROJECT_ID

次のコマンドを実行して、テナント プロジェクトにログバケットを作成します。ログバケット名は、クラスタ Google Cloud プロジェクトの ID にする必要があります。これは変更できません。

gcloud alpha logging buckets \
   create $CLUSTER_PROJECT_ID \
   --location=global \
   --project=$TENANT_PROJECT_ID

次のコマンドを実行して、クラスタ Google Cloud プロジェクト内の指定した Namespace からテナント Google Cloud プロジェクト バケットにシンクを作成します。ログの範囲を限定することもできます。たとえば、追加の log-filterを定義して、個々の GKE クラスタまたは特定の Cloud Run for Anthos リソースのみを共有できます。

gcloud alpha logging sinks \
   create $SINK_NAME \
   logging.googleapis.com/projects/$TENANT_PROJECT_ID/locations/global/buckets/$CLUSTER_PROJECT_ID \
   --log-filter=resource.labels.namespace_name=$NAMESPACE \
   --project $CLUSTER_PROJECT_ID

次のコマンドを実行して、ログシンク サービス アカウントから作成したバケットに権限を追加します。

export SINK_SERVICE_ACCOUNT=$(gcloud alpha logging sinks \
   describe $SINK_NAME \
   --project $CLUSTER_PROJECT_ID \
   --format="value(writerIdentity)")
gcloud projects add-iam-policy-binding $TENANT_PROJECT_ID \
   --member=$SINK_SERVICE_ACCOUNT \
   --role='roles/logging.bucketWriter' \
   --condition="expression=resource.name.endsWith\
   (\"locations/global/buckets/$CLUSTER_PROJECT_ID\"),\
   title=Log bucket writer from $CLUSTER_PROJECT_ID"

ロールベースのアクセス制御(RBAC)によるテナントの権限の設定

Google グループと IAM を使用して、テナントが GKE クラスタの Google Cloud プロジェクトにアクセスするための権限を構成しました。テナントが GKE クラスタ内のリソースにアクセスするには、Kubernetes RBAC で権限を定義する必要があります。

クラスタロールの作成

次のクラスタロールを定義して作成した後は、引き続きこれらのロールを使用して、クラスタ Google Cloud プロジェクトのテナントを追加できます。

UI ロール

このロールにより、テナントはすべての Namespace を照会できます。これは、ユーザーが /sdk/gcloud/reference/alpha/logging/sinks/create サービスの作成でアクセスする Namespace を検索する際に必要になります。

kubectl create clusterrole \
   namespace-lister \
   --verb=list \
   --resource=namespaces

このロールにより、テナントは Cloud Run for Anthos サービスを表示できます。これは、Cloud Run for Anthos UI でサービスの一覧を表示するために必要です。

kubectl create clusterrole \
   ksvc-lister \
   --verb=list \
   --resource=services.serving.knative.dev

クラスタロールの作成

これらの権限の中で、いずれか 1 つが必要になります。最初の権限により、テナントは Namespace 内のすべてのリソースを操作できます。2 番目の権限で、Cloud Run for Anthos サービスの作成に限定された操作が許可されます。

kubectl create clusterrole \
   kubernetes-developer \
   --verb="*" \
   --resource="*.*"

kubernetes-developer 権限の制限が大きすぎる場合は、以下の操作により、テナントの Namespace での Knative サービスの作成と他の Knative リソースの表示をテナントに許可できます。

cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: knative-developer
rules:
- apiGroups: ["serving.knative.dev"]
  resources: ["services"]
  verbs: ["*"]
- apiGroups: ["serving.knative.dev"]
  resources: ["*"]
  verbs: ["get", "list", "watch"]
EOF

テナントの Namespace を作成して権限を割り当てる

ここでは、GKE 向け Google グループが設定済みであることを前提としています。これはテナントごとに行う必要があります。

export TENANT_GROUP=tenant-a@company.com

TENANT_GROUP は SECURITY_GROUP の一部である必要があります。

すべての Namespace を表示する権限

GKE クラスタにクエリを実行するため、すべてのテナントには Namespace の一覧を取得する権限があります。現時点で、アクションが利用可能な Namespace を返す auth can-i はありません。唯一の回避策は、Namespace の一覧を取得してから、Namespace ごとに個別にクエリを実行することです。

kubectl create clusterrolebinding \
   all-namespace-listers \
   --clusterrole=namespace-lister \
   --group=$TENANT_GROUP

Cloud Run for Anthos サービスの一覧を取得する権限

kubectl create clusterrolebinding \
   all-ksvc-listers \
   --clusterrole=ksvc-lister \
   --group=$TENANT_GROUP

Namespace のリソースを操作する権限

まず、Namespace を作成します。

kubectl create namespace $NAMESPACE

kubernetes-developer ロールを使用する場合:

kubectl create rolebinding \
   kubernetes-developer \
   --namespace=$NAMESPACE \
   --clusterrole=kubernetes-developer \
   --group=$TENANT_GROUP

knative-developer ロールを使用する場合:

kubectl create rolebinding \
   kubernetes-developer \
   --namespace=$NAMESPACE \
   --clusterrole=knative-developer \
   --group=$TENANT_GROUP

テナントが外部 IP アドレスにアクセスできるように権限を追加する

cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: ingress-reader
rules:
- apiGroups: [""]
  resources: ["services"]
  verbs: ["get"]
EOF
kubectl create rolebinding \
   ingress-reader-$TENANT_GROUP \
   --namespace=gke-system \
   --clusterrole=ingress-reader \
   --group=$TENANT_GROUP

確認

Cloud Run for Anthos でテナント Google Cloud プロジェクトを開き、クラスタ Google Cloud プロジェクトのクラスタにサービスをデプロイすることで、エンタープライズ マルチテナンシーが正常に構成されていることを確認できます。

Cloud Run for Anthos に移動します。

これで、アクセスが許可されている GKE クラスタの名前空間内のサービスとリソースをテナントで操作できるようになりました。

マルチテナンシーのリファレンス