Multilocação entre projetos para o Knative serving

Este guia orienta você na configuração do Knative serving para permitir um ou mais projetos do Google Cloud para executar e gerenciar as cargas de trabalho em execução em um cluster do GKE em outro projeto do Google Cloud.

Um modelo operacional comum com o Knative serving é para que uma equipe de desenvolvedores de aplicativos use o projeto do Google Cloud para implantar e gerenciar serviços executados em diferentes clusters do GKE em projetos do Google Cloud de outras equipes. Esse recurso, chamado multilocação, permite que você, como operador da plataforma, adapte suas equipes de desenvolvimento somente aos serviços em execução nos diversos ambientes da sua organização (por exemplo, produção e preparação).

O Knative serving é compatível especificamente com a multilocação empresarial. Esse tipo de multilocação ativa um projeto de cluster do Google Cloud para permitir o acesso a recursos específicos do cluster do GKE. O projeto do Google Cloud que tem acesso ao projeto de cluster do Google Cloud é o projeto de locatário do Google Cloud. Os locatários do projeto de cluster do Google Cloud podem usar o Knative serving para acessar, operar e ser proprietários desses serviços e recursos a que eles têm acesso.

Conceitualmente, há quatro etapas para configurar a multilocação empresarial com o Knative serving:

  1. Configurar o acesso do locatário ao projeto de cluster do Google Cloud usando um Grupo do Google e o Identity and Access Management.
  2. Mapear cada projeto de locatário do Google Cloud para o projeto de cluster do Google Cloud
  3. Encaminhar os dados de registro do projeto de cluster do Google Cloud para os projetos do Google Cloud do locatário usando coletores e buckets de registro.
  4. Definir permissões de cluster para locatários usando o controle de acesso baseado em papéis.

Antes de começar

O operador da plataforma responsável pela configuração da multilocação precisa entender e atender aos requisitos a seguir:

Defina as variáveis de ambiente locais

Para simplificar os comandos usados neste processo, defina variáveis de ambiente locais para o projeto de cluster do Google Cloud e o projeto de locatário do Google Cloud:

  1. Substitua YOUR_CLUSTER_PROJECT_ID pelo ID do projeto de cluster do Google Cloud e execute o comando a seguir:

    export CLUSTER_PROJECT_ID=YOUR_CLUSTER_PROJECT_ID
    
  2. Substitua YOUR_TENANT_PROJECT_ID pelo ID do projeto de locatário do Google Cloud e execute o comando a seguir:

    export TENANT_PROJECT_ID=$YOUR_TENANT_PROJECT_ID
    
  3. Verifique as variáveis de ambiente locais executando os comandos a seguir:

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

O ID do projeto do cluster do Google Cloud e o ID do projeto de locatária do Google Cloud agora são usados em todos os comandos a seguir, em que $CLUSTER_PROJECT_ID e $TENANT_PROJECT_ID são especificados.

Verificação das permissões do IAM

Execute os comandos testIamPermissions a seguir para confirmar que você tem as permissões necessárias do IAM para acessar os recursos no projeto de cluster do Google Cloud e nos projetos do Google Cloud do locatário.

Execute o seguinte comando para validar suas permissões no projeto de cluster do 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

Resultados esperados para o projeto de cluster do Google Cloud:

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

Execute o seguinte comando para validar suas permissões em cada projeto de locatário do 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

Resultados esperados para cada projeto de locatário do Google Cloud:

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

Usar um Grupo do Google e o gerenciamento de identidade e acesso para configurar o acesso do locatário

Usar um Grupo do Google para permitir que os locatários acessem o cluster do GKE. Com as permissões do IAM, os locatários podem acessar as credenciais, mas não podem fazer nada no cluster até que o controle de acesso baseado em papéis do Kubernetes seja configurado em uma etapa posterior.

Você precisa criar um Grupo do Google com todos os usuários do projeto de locatário do Google Cloud. Para mais informações sobre como usar um grupo de segurança, consulte Como usar Grupos do Google para o GKE.

Crie a seguinte variável de ambiente local para seu Grupo do Google:

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

Leitor de cluster do Kubernetes

Execute os comandos a seguir para permitir que os locatários consigam credenciais no cluster. Isso não permite que eles leiam ou manipulem recursos no cluster do GKE.

Referência do IAM

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

Para restringir o acesso a um cluster específico, use uma condição do 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"

Leitor do Monitoring

Execute o comando a seguir para permitir que os locatários leiam as métricas de monitoramento.

Referência dos papéis do Monitoring

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

Como mapear cada projeto de locatário do Google Cloud para o projeto de cluster do Google Cloud

Use valores de configuração de recursos para mapear projetos de locatário do Google Cloud para um projeto de cluster do Google Cloud.

A configuração de recursos pode ser definida para cada projeto de locatário do Google Cloud ou pode ser definida em qualquer nível da hierarquia de pastas. É mais fácil definir isso no nível da pasta do locatário individual, mas é mais flexível definir isso no nível do projeto de cada locatário. Após a configuração, sempre que os locatários navegarem pela interface do Knative serving, eles também vão encontrar os serviços no projeto de cluster do Google Cloud. Isso não altera as permissões do IAM no projeto de cluster do Google Cloud ou nos clusters do GKE. É apenas um mapeamento de um projeto (ou pasta) do locatário para um projeto de cluster do Google Cloud.

  1. Ative a API resourcesettings no projeto de cluster do Google Cloud.

    gcloud services enable resourcesettings.googleapis.com \
      --project=$TENANT_PROJECT_ID
    
  2. Execute o seguinte comando para adicionar os privilégios de administrador da organização (roles/resourcesettings.admin) ao seu ID de usuário:

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

    Substitua YOUR_ORGANIZATION_ID pelo ID da organização e YOUR_ADMIN_MEMBER_ID pelo ID do usuário, por exemplo, user:my-email@my-domain.com.

  3. Escolha um dos métodos a seguir para definir o mapeamento.

    É possível definir o valor da configuração do recurso em uma pasta pai do Google Cloud se todos os projetos filhos do Google Cloud e as pastas do Google Cloud usarem esse mesmo valor.

Projetos de locatário

Defina o valor da configuração de recursos para cada projeto de locatário do Google Cloud:

  1. Consiga o name do projeto de locatário do Google Cloud e defina-o como uma variável de ambiente local:
    export TENANT_PROJECT_NUMBER=$(gcloud projects describe $TENANT_PROJECT_ID --format="value(projectNumber)")
  2. Crie um arquivo de valor de configuração de recursos para definir o mapeamento do projeto de locatário do Google Cloud para o projeto de cluster do Google Cloud. Vários IDs de projeto de cluster do Google Cloud podem ser definidos nesse arquivo e adicionados a um único projeto de locatário do 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. Implante as configurações de recursos no projeto de locatário do Google Cloud:
    gcloud resource-settings set-value cloudrun-multiTenancy --value-file value-file.json --project $TENANT_PROJECT_ID

Pastas de locatário

Defina o valor da configuração de recursos em uma pasta de locatário pai para definir esse valor para todas as pastas e projetos filhos de locatário do Google Cloud:

  1. Consiga o number da pasta de locatário e defina-o como uma variável de ambiente local:
    export TENANT_FOLDER_NUMBER=$TENANT_FOLDER_NUMBER
  2. Crie um arquivo de valor de configuração de recursos para definir o mapeamento da pasta de locatário para o projeto de cluster do Google Cloud. Vários IDs de projeto de cluster do Google Cloud podem ser definidos nesse arquivo e adicionados a uma única pasta de locatário.
    cat > value-file.json << EOF
    {
    "name": "folders/$TENANT_FOLDER_NUMBER/settings/cloudrun-multiTenancy/value",
    "value": {
      "stringSetValue": {
        "values": [ "projects/$CLUSTER_PROJECT_ID" ]
      }
    }
    }
    EOF
  3. Implante as configurações de recursos na pasta de locatário:
    gcloud resource-settings set-value cloudrun-multiTenancy --value-file value-file.json --folder $TENANT_FOLDER_NUMBER

Como configurar coletores e buckets de registros para rotear dados de registro

Para cada locatário, você cria um bucket de registro, um coletor e as permissões para rotear os dados de registro do projeto de cluster do Google Cloud para o projeto de locatário do Google Cloud. Nas etapas a seguir, todos os registros do namespace no projeto de cluster do Google Cloud serão roteados para o bucket. Consulte o conjunto abaixo para ver detalhes sobre como limitar quais registros são compartilhados.

Crie as seguintes variáveis de ambiente locais:

  • Especifique o namespace do cluster do GKE que os locatários acessam.
  • O nome do coletor. Para simplificar essa etapa, o nome é uma combinação do projeto de cluster do Google Cloud com as variáveis de ambiente locais do projeto de locatário do Google Cloud criadas anteriormente. É possível modificar esse valor.
export NAMESPACE=$NAMESPACE
export SINK_NAME=$CLUSTER_PROJECT_ID-$TENANT_PROJECT_ID

Execute o comando a seguir para criar o bucket de registros no projeto de locatário. Observe que o nome do bucket de registro precisa ser o ID do projeto de cluster do Google Cloud e não pode ser alterado ou modificado.

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

Execute o comando a seguir para criar o coletor do namespace especificado no projeto de cluster do Google Cloud para o bucket do projeto de locatário do Google Cloud. É possível restringir o escopo dos registros, por exemplo, para compartilhar apenas clusters individuais do GKE ou recursos específicos do Knative serving, definindo valores log-filter adicionais.

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

Execute os comandos a seguir para adicionar a permissão da conta de serviço do coletor de registros ao bucket criado.

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"

Configuração de permissões de locatário com controle de acesso baseado em papéis (RBAC)

Você usou anteriormente Grupos do Google e o IAM para configurar permissões e permitir que os locatários acessem o projeto do Google Cloud do cluster do GKE. Para permitir que os locatários acessem os recursos no cluster do GKE, você precisa definir permissões com o RBAC do Kubernetes.

Criar papéis de cluster

Depois de definir e criar os papéis de cluster a seguir, é possível continuar a usá-los no futuro para adicionar todos os locatários subsequentes do projeto de cluster do Google Cloud.

Papéis de IU

Com esse papel, os locatários podem consultar todos os namespaces. Isso é necessário para descobrir quais namespaces os usuários têm acesso para criar serviços /sdk/gcloud/reference/logging/sinks/create.

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

Esse papel permite que os locatários visualizem serviços do Knative serving. Isso é necessário para listar os serviços na interface do Knative serving.

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

Criar papéis de cluster

Apenas uma dessas permissões é necessária. A primeira permissão admite que os locatários manipulem qualquer recurso no seu namespace. A segunda permissão permite um conjunto mais limitado apenas para criar serviços do Knative serving.

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

Se a permissão kubernetes-developer for muito permissiva, o código a seguir admitirá que os locatários criem serviços do Knative nos seus namespaces e vejam os outros recursos do 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

Crie namespace de locatário e atribua permissões.

Isso pressupõe que você configurou usando o Grupos do Google para o GKE. Isso é necessário para cada locatário.

export TENANT_GROUP=tenant-a@company.com

TENANT_GROUP precisa parte de SECURITY_GROUP

Capacidade de visualizar todos os namespaces

Para consultar o cluster do GKE, todos os locatários precisam da capacidade de listar namespaces. Atualmente, não há um auth can-i que retorna namespaces para os quais uma ação é possível. A única solução é listar os namespaces e, em seguida, consultar cada namespace individualmente.

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

Capacidade de listar os serviços do Knative serving

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

Capacidade de manipular recursos no namespace

Primeiro, crie o namespace:

kubectl create namespace $NAMESPACE

Se estiver usando o papel kubernetes-developer:

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

Se estiver usando o papel knative-developer:

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

Adicione a possibilidade de o locatário acessar o endereço IP externo

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

Verificar

Para verificar se você configurou corretamente a multilocação empresarial, abra o projeto do Google Cloud do locatário no Knative serving e implante um serviço em um cluster do GKE.

Acessar o Knative serving

Parabéns, agora seu locatário pode interagir com os serviços e recursos dentro do namespace do cluster do GKE a que ele recebeu acesso.

Referência de multilocação