Knative serving을 위한 프로젝트 간 멀티테넌시

이 가이드에서는 하나 이상의 Google Cloud 프로젝트가 다른 Google Cloud 프로젝트의 GKE 클러스터에서 실행되는 워크로드를 실행하고 관리할 수 있도록 Knative serving을 구성하는 방법을 설명합니다.

Knative serving의 일반적인 작동 모델은 애플리케이션 개발자 팀이 다른 팀의 Google Cloud 프로젝트에 있는 서로 다른 GKE 클러스터에서 실행되는 서비스를 배포하고 관리하기 위해 해당 Google Cloud 프로젝트를 사용하는 경우입니다. 멀티테넌시라고 부르는 이 기능을 사용하면 플랫폼 운영자로서 개발 팀이 조직의 여러 환경(예: 프로덕션과 스테이징)에서 실행되는 서비스에만 액세스하도록 조정할 수 있습니다.

Knative serving은 특히 엔터프라이즈 멀티테넌시를 지원합니다. 이 유형의 멀티테넌시는 Google Cloud 클라우드 프로젝트가 해당 GKE 클러스터의 특정 리소스에 대한 액세스를 허용하도록 설정합니다. 클러스터 Google Cloud 프로젝트에 액세스 권한이 부여되는 Google Cloud 프로젝트는 테넌트 Google Cloud 프로젝트입니다. 클러스터 Google Cloud 프로젝트의 테넌트는 Knative serving을 사용하여 액세스 권한이 부여된 서비스 및 리소스만 액세스하고, 작업을 수행하고, 소유할 수 있습니다.

개념적으로 Knative serving으로 엔터프라이즈 멀티테넌시를 구성하는 데에는 4단계가 있습니다.

  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를 클러스터 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
    

클러스터 Google Cloud 프로젝트 ID 및 테넌트 Google Cloud 프로젝트 ID는 이제 $CLUSTER_PROJECT_ID$TENANT_PROJECT_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 프로젝트에 대해 구성하거나, 폴더 계층 구조의 임의 수준에 설정될 수 있습니다. 단일 테넌트 폴더 수준에서 이를 설정하는 것이 더 쉽지만, 각 테넌트 프로젝트 수준에 설정하는 것이 더 유연합니다. 이 설정 후에는 테넌트가 Knative serving UI를 탐색할 때마다 클러스터 Google Cloud 프로젝트에 해당 서비스가 표시됩니다. 이렇게 해도 클러스터 Google 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 클라우드 폴더에 동일한 값이 사용될 경우 상위 Google 클라우드 폴더에서 리소스 설정 값을 설정할 수 있습니다.

테넌트 프로젝트

각 테넌트 Google Cloud 프로젝트에 대해 리소스 설정 값을 설정합니다.

  1. 테넌트 Google Cloud 프로젝트의 name을 가져오고 이를 로컬 환경 변수로 설정합니다.
    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

로그 데이터를 라우팅하도록 로그 버킷 및 싱크 설정

각 테넌트에 대해 클러스터 Google Cloud 프로젝트 로그 데이터를 테넌트 Google Cloud 프로젝트로 라우팅하도록 로그 버킷, 싱크, 권한을 만듭니다. 다음 단계에서는 클러스터 Google Cloud 프로젝트에 있는 네임스페이스의 모든 로그가 버킷으로 라우팅됩니다. 공유할 로그를 제한하는 방법에 대한 자세한 내용은 아래 설정을 참조하세요.

다음 로컬 환경 변수를 만듭니다.

  • 테넌트가 액세스하는 GKE 클러스터의 네임스페이스를 지정합니다.
  • 싱크의 이름입니다. 이 단계를 단순화하기 위해 이름은 클러스터 Google Cloud 프로젝트와 이전에 만든 테넌트 Google Cloud 프로젝트 로컬 환경 변수의 조합입니다. 이 값은 수정할 수 있습니다.
export NAMESPACE=$NAMESPACE
export SINK_NAME=$CLUSTER_PROJECT_ID-$TENANT_PROJECT_ID

다음 명령어를 실행하여 테넌트 프로젝트에 로그 버킷을 만듭니다. 로그 버킷 이름은 클러스터 Google Cloud 프로젝트의 ID여야 하며, 변경 또는 수정될 수 없습니다.

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

다음 명령어를 실행하여 클러스터 Google Cloud 프로젝트의 지정된 네임스페이스로부터 테넌트 Google Cloud 프로젝트 버킷으로 싱크를 만듭니다. 추가적인 log-filter을 정의하여 개별 GKE 클러스터만 공유하거나 특정 Knative serving 리소스만 공유하도록 하는 등 로그 범위를 좁힐 수 있습니다.

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 클러스터 네임스페이스 내에서 서비스 및 리소스와 상호작용할 수 있습니다.

멀티테넌시 참조