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

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

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

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

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

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

始める前に

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

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

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

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

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

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

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

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

IAM 権限の確認

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

次のコマンドを実行して、クラスタ 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

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

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

各テナント 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

各テナント 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 ロールベースのアクセス制御を構成するまで、クラスタ内では何もできません。

テナント 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

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

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

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

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

    gcloud services enable resourcesettings.googleapis.com \
      --project=$TENANT_PROJECT_ID
    
  2. 次のいずれかの方法でマッピングを定義します。

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

テナント プロジェクト

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

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

テナント フォルダ

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

  1. テナント フォルダの number を取得し、ローカル環境変数に設定します。
    export TENANT_FOLDER_NUMBER=$TENANT_FOLDER_NUMBER
    
  2. リソース設定値ファイルを作成して、テナント フォルダからクラスタ Cloud プロジェクトへのマッピングを定義します。このファイルに複数のクラスタ 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
    

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

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

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

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

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

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

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

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 クラスタの Cloud プロジェクトにアクセスするための権限を構成しました。テナントが GKE クラスタ内のリソースにアクセスするには、Kubernetes RBAC で権限を定義する必要があります。

クラスタロールの作成

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

UI ロール

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

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

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

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

クラスタロールの作成

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

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

kubernetes-developer 権限の制限が大きすぎる場合は、以下の操作により、テナントの名前空間での 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

テナントの名前空間を作成して権限を割り当てる

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

export TENANT_GROUP=tenant-a@company.com

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

すべての名前空間を表示する権限

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

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

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

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

名前空間のリソースを操作する権限

まず、名前空間を作成します。

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

Cloud Run に移動します

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

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