Knative serving 的跨專案多租戶架構

本指南將逐步說明如何設定 Knative Serving,允許一或多個 Google Cloud 專案執行及管理在不同 Google Cloud 專案的 GKE 叢集上執行的工作負載。

使用 Knative Serving 時,常見的作業模式是應用程式開發人員團隊使用 Google Cloud 專案,部署及管理在其他團隊Google Cloud 專案中不同 GKE 叢集執行的服務。這項功能稱為「多租戶架構」,可讓平台營運人員為開發團隊調整存取權,只允許他們存取在貴機構各種環境 (例如正式版與預先發布版) 中執行的服務。

Knative serving 專門支援企業多租戶。這類多租戶可讓叢集 Google Cloud 專案存取 GKE 叢集的特定資源。 Google Cloud 獲准存取叢集 Google Cloud 專案的專案是租戶 Google Cloud 專案。叢集 Google Cloud 專案的租戶可以使用 Knative serving 存取、操作及擁有獲授權的服務和資源。

從概念上來說,使用 Knative Serving 設定企業多租戶功能時,有四個步驟:

  1. 使用 Google 群組和 Identity and Access Management,設定租戶對叢集 Google Cloud 專案的存取權。
  2. 將每個租戶 Google Cloud 專案對應至叢集 Google Cloud 專案。
  3. 使用記錄檔值區和接收器,將叢集 Google Cloud 專案記錄資料傳送至租戶 Google Cloud 專案。
  4. 使用角色型存取權控管,為租戶定義叢集權限。

事前準備

負責設定多重租戶的平台營運商必須瞭解並符合下列需求:

定義本機環境變數

為簡化這個程序中使用的指令,請為叢集 Google Cloud 專案和租戶 Google Cloud 專案定義本機環境變數:

  1. YOUR_CLUSTER_PROJECT_ID 替換為叢集專案的 ID,然後執行下列指令: Google Cloud

    export CLUSTER_PROJECT_ID=YOUR_CLUSTER_PROJECT_ID
    
  2. YOUR_TENANT_PROJECT_ID 替換為租戶專案的 ID,然後執行下列指令: Google Cloud

    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 群組和身分與存取權管理設定房客存取權

使用 Google 群組允許房客存取 GKE 叢集。 IAM 權限可讓租戶取得憑證,但必須在後續步驟中設定 Kubernetes 角色式存取控管,租戶才能在叢集中執行任何操作。

您必須建立包含所有房客 Google Cloud 專案使用者的 Google 群組。 如要進一步瞭解如何使用安全性群組,請參閱「將 Google 群組用於 GKE」。

為 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 專案設定資源,也可以在資料夾階層的任何層級設定資源。在單一租戶資料夾層級設定較為簡單,但在每個租戶專案層級設定則更具彈性。設定完成後,房客瀏覽 Knative Serving UI 時,也會在叢集 Google Cloud 專案中看到自己的服務。這不會變更叢集專案或 GKE 叢集的 IAM 權限,只會將租戶專案 (或資料夾) 對應至叢集專案。 Google Cloud Google Cloud

  1. 在租戶 Google Cloud 專案中啟用 resourcesettings API。

    gcloud services enable resourcesettings.googleapis.com \
      --project=$TENANT_PROJECT_ID
    
  2. 執行下列指令,將機構管理員權限 (roles/resourcesettings.admin) 新增至使用者 ID:

    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. 取得租戶專案的 name Google Cloud ,並將其設為本機環境變數:
    export TENANT_PROJECT_NUMBER=$(gcloud projects describe $TENANT_PROJECT_ID --format="value(projectNumber)")
  2. 建立資源設定值檔案,定義從租戶 Google Cloud 專案到叢集 Google Cloud 專案的對應關係。您可以在這個檔案中定義多個叢集 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 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,並新增至單一租戶資料夾。
    cat > value-file.json << EOF
    {
    "name": "folders/$TENANT_FOLDER_NUMBER/settings/cloudrun-multiTenancy/value",
    "value": {
      "stringSetValue": {
        "values": [ "projects/$CLUSTER_PROJECT_ID" ]
      }
    }
    }
    EOF
  3. 將資源設定部署至租戶資料夾:
    gcloud resource-settings set-value cloudrun-multiTenancy --value-file value-file.json --folder $TENANT_FOLDER_NUMBER

設定記錄檔 bucket 和接收器,以轉送記錄資料

針對每個租戶,您要建立記錄值區、接收器,以及將叢集 Google Cloud 專案記錄資料傳送至租戶 Google Cloud 專案的權限。在下列步驟中,叢集 Google Cloud 專案中命名空間的所有記錄檔都會傳送至該值區。如要進一步瞭解如何限制共用的記錄,請參閱下方設定。

建立下列本機環境變數:

  • 指定租戶可存取的 GKE 叢集命名空間。
  • 接收器的名稱。為簡化這個步驟,名稱會結合您先前建立的叢集 Google Cloud 專案和租戶 Google Cloud 專案本機環境變數。您可以修改這個值。
export NAMESPACE=$NAMESPACE
export SINK_NAME=$CLUSTER_PROJECT_ID-$TENANT_PROJECT_ID

執行下列指令,在租戶專案中建立記錄 bucket。請注意,記錄值區名稱必須是叢集專案的 ID Google Cloud ,且無法變更或修改。

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

執行下列指令,在叢集 Google Cloud 專案的指定命名空間中建立接收器,並將資料傳送至租戶 Google Cloud 專案 bucket。請注意,您可以縮小記錄的範圍,例如定義其他 log-filter,只分享個別 GKE 叢集或特定 Knative 服務資源。

gcloud 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 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 角色

這個角色可讓租戶查詢所有命名空間。這是必要步驟,可找出使用者有權建立 /sdk/gcloud/reference/logging/sinks/create 服務的命名空間。

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

這個角色可讓租戶查看 Knative serving 服務。這是列出 Knative serving UI 中服務的必要條件。

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

建立叢集角色

您只需要其中一項權限。第一個權限可讓租戶操控命名空間中的任何資源。第二個權限則允許建立 Knative serving 服務,但權限較為受限。

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

能夠列出 Knative serving 服務

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=istio-system \
   --clusterrole=ingress-reader \
   --group=$TENANT_GROUP

驗證

如要確認是否已成功設定企業多租戶,請在 Knative Serving 中開啟租戶 Google Cloud 專案,並將服務部署至 GKE 叢集。

前往 Knative serving

恭喜!現在租戶可以與已獲授權的 GKE 叢集命名空間內服務和資源互動。

多租戶參考資料