Multiusuario entre proyectos para la entrega de Knative

En esta guía, se explica cómo configurar la entrega de Knative para permitir que uno o más proyectos de Google Cloud ejecuten y administren las cargas de trabajo que se ejecutan en un clúster de GKE en un proyecto de Google Cloud diferente.

Un modelo operativo común con la entrega de Knative es que un equipo de desarrolladores de aplicaciones use su proyecto de Google Cloud para implementar y administrar servicios que se ejecutan en clústeres de GKE dispares en los proyectos de Google Cloud de otros equipos. Esta capacidad, que se llama multiusuario, te permite, como operador de la plataforma, adaptar el acceso de los equipos de desarrollo solo a sus servicios que se ejecutan en tus organizaciones en varios entornos (por ejemplo, producción frente a etapa de pruebas).

La entrega de Knative admite de manera específica multiusuarios empresariales. Este tipo de multiusuario habilita un proyecto de Google Cloud de clúster para permitir el acceso a recursos específicos de su clúster de GKE. El proyecto de Google Cloud al que se le otorga acceso al proyecto de clúster de Google Cloud es el proyecto de usuario de Google Cloud. Los usuarios del proyecto de Google Cloud del clúster pueden usar la entrega de Knative para acceder a esos servicios y recursos, operar en ellos y poseerlos.

De forma conceptual, existen cuatro pasos para configurar el multiusuario empresarial con la entrega de Knative:

  1. Configurar el acceso de los usuarios al proyecto de Google Cloud del clúster mediante un Grupo de Google y Identity and Access Management
  2. Asignar cada proyecto de usuario de Google Cloud al proyecto de clúster de Google Cloud
  3. Enrutar los datos de registro del proyecto de Google Cloud del clúster a los proyectos de Google Cloud de usuarios mediante receptores y buckets de registros
  4. Definir los permisos del clúster para usuarios mediante el control de acceso basado en funciones

Antes de comenzar

El operador de la plataforma que es responsable de la configuración de multiusuario debe conocer y cumplir los siguientes requisitos:

Define las variables de entorno local

A fin de simplificar los comandos que se usan en este proceso, define las variables de entorno local para el proyecto de Google Cloud de clúster y el proyecto de Google Cloud de usuario:

  1. Reemplaza YOUR_CLUSTER_PROJECT_ID por el ID del proyecto de clúster de Google Cloud y, luego, ejecuta el siguiente comando:

    export CLUSTER_PROJECT_ID=YOUR_CLUSTER_PROJECT_ID
    
  2. Reemplaza YOUR_TENANT_PROJECT_ID por el ID del proyecto de Google Cloud de usuario y, luego, ejecuta el siguiente comando:

    export TENANT_PROJECT_ID=$YOUR_TENANT_PROJECT_ID
    
  3. Ejecuta los siguientes comandos para verificar las variables de entorno local:

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

El ID del proyecto de Google Cloud del clúster y el ID del proyecto de Google Cloud de usuario ahora se usan en todos los comandos siguientes en los que se especifican $CLUSTER_PROJECT_ID y $TENANT_PROJECT_ID.

Verifica los permisos de IAM

Ejecuta los siguientes comandos testIamPermissions a fin de validar que tienes los permisos de IAM necesarios para acceder a los recursos en el proyecto del clúster de Google Cloud y en los proyectos de Google Cloud de usuario.

Ejecuta el siguiente comando para validar tus permisos en el proyecto de clúster de 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 el proyecto de clúster de Google Cloud:

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

Ejecuta el siguiente comando para validar tus permisos en cada proyecto de Google Cloud de usuario:

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 proyecto de Google Cloud de usuario:

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

Usa un Grupo de Google y la administración de identidades y accesos para configurar el acceso de los usuarios

Usa un Grupo de Google para permitir que los usuarios accedan al clúster de GKE. Los permisos de IAM otorgan a los usuarios los permisos para obtener credenciales, pero no podrán realizar ninguna acción en el clúster hasta que el control de acceso basado en funciones de Kubernetes se configure en un paso posterior.

Debes crear un Grupo de Google que contenga todos los usuarios del proyecto de usuario de Google Cloud. A fin de obtener más información para usar un grupo de seguridad, consulta Usa Grupos de Google para GKE.

Crea la siguiente variable de entorno local para el Grupo de Google:

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

Visualizador de clústeres de Kubernetes

Ejecuta los siguientes comandos para permitir que los usuarios obtengan credenciales en el clúster. Esto no permite que los usuarios lean ni manipulen ningún recurso en el clúster de GKE.

Referencia de IAM

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

Para restringir el acceso a un clúster específico, puedes usar una condición de 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"

Visualizador de Monitoring

Ejecuta el siguiente comando para permitir que los usuarios lean las métricas de supervisión.

Referencia de las funciones de Monitoring

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

Asigna cada proyecto de Google Cloud de usuario al proyecto de Google Cloud de clúster

Debes usar valores de configuración de recursos para asignar proyectos de Google Cloud de usuario a un proyecto de Google Cloud de clúster.

La configuración de recursos se puede configurar para cada proyecto de Google Cloud de usuario individual o se puede establecer en cualquier nivel de la jerarquía de carpetas. Es más fácil configurar esta opción a nivel de carpeta de usuario único, pero configurarla a nivel de proyecto de cada usuario brinda mayor flexibilidad. Después de esta configuración, cada vez que los usuarios exploren la IU de entrega de Knative, también verán sus servicios en el proyecto de clúster de Google Cloud. Esto no cambia los permisos de IAM en el proyecto de Google Cloud del clúster ni en los clústeres de GKE; solo es una asignación de un proyecto de usuario (o carpeta) a un proyecto de Google Cloud de clúster.

  1. Habilita la API de resourcesettings en el proyecto de Google Cloud de usuario.

    gcloud services enable resourcesettings.googleapis.com \
      --project=$TENANT_PROJECT_ID
    
  2. Para agregar los privilegios de administrador de la organización (roles/resourcesettings.admin) al ID del usuario, ejecuta el siguiente comando:

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

    Reemplaza YOUR_ORGANIZATION_ID con el ID de tu organización y YOUR_ADMIN_MEMBER_ID con el ID de usuario, por ejemplo user:my-email@my-domain.com.

  3. Elige uno de los siguientes métodos para definir el mapeo.

    Puedes establecer el valor de configuración de recursos en una carpeta superior de Google Cloud si todos los proyectos secundarios y las carpetas de Google Cloud usan ese mismo valor.

Proyectos de usuarios

Establece el valor de configuración de recursos para cada proyecto de usuario de Google Cloud:

  1. Obtén el name del proyecto de Google Cloud de usuario y configúralo en una variable de entorno local:
    export TENANT_PROJECT_NUMBER=$(gcloud projects describe $TENANT_PROJECT_ID --format="value(projectNumber)")
  2. Crea un archivo de valor de configuración de recursos para definir la asignación del proyecto de Google Cloud de usuario al proyecto de Google Cloud del clúster. En este archivo, se pueden definir varios IDs de proyectos de Google Cloud de clústeres y agregarlos a un proyecto de Google Cloud de usuario único.
    cat > value-file.json << EOF
    {
    "name": "projects/$TENANT_PROJECT_NUMBER/settings/cloudrun-multiTenancy/value",
    "value": {
      "stringSetValue": {
        "values": [ "projects/$CLUSTER_PROJECT_ID" ]
      }
    }
    }
    EOF
    
  3. Implementa la configuración de recursos en el proyecto de usuario de Google Cloud:
    gcloud resource-settings set-value cloudrun-multiTenancy --value-file value-file.json --project $TENANT_PROJECT_ID

Carpetas de usuarios

Establece el valor de configuración de recursos de una carpeta de usuario superior para establecer ese valor en todos los proyectos y carpetas de Google Cloud de usuario secundario:

  1. Obtén el number de la carpeta de usuario y configúralo como una variable de entorno local:
    export TENANT_FOLDER_NUMBER=$TENANT_FOLDER_NUMBER
    
  2. Crea un archivo de valor de configuración de recursos para definir la asignación de la carpeta de usuario al proyecto de Google Cloud del clúster. En este archivo, se pueden definir varios IDs de proyectos de Google Cloud de clústeres y agregarlos a una carpeta de usuario único.
    cat > value-file.json << EOF
    {
    "name": "folders/$TENANT_FOLDER_NUMBER/settings/cloudrun-multiTenancy/value",
    "value": {
      "stringSetValue": {
        "values": [ "projects/$CLUSTER_PROJECT_ID" ]
      }
    }
    }
    EOF
    
  3. Implementa la configuración de recursos en la carpeta de usuario:
    gcloud resource-settings set-value cloudrun-multiTenancy --value-file value-file.json --folder $TENANT_FOLDER_NUMBER

Configura los receptores y buckets de registros para enrutar los datos de registro

Por cada usuario, debes crear un bucket de registros, un receptor y los permisos para enrutar los datos de registro del proyecto de Google Cloud del clúster al proyecto de Google Cloud de usuario. En los siguientes pasos, todos los registros del espacio de nombres en el proyecto de Google Cloud de clúster se enrutan al bucket. Consulta el siguiente conjunto para obtener detalles sobre cómo limitar los registros que se comparten.

Crea las siguientes variables de entorno local:

  • Especifica el espacio de nombres del clúster de GKE al que acceden los usuarios.
  • El nombre del receptor. Para simplificar este paso, el nombre es una combinación de las variables de entorno local del proyecto de Google Cloud del clúster y del proyecto de Google Cloud de usuario que creaste antes. Puedes modificar este valor.
export NAMESPACE=$NAMESPACE
export SINK_NAME=$CLUSTER_PROJECT_ID-$TENANT_PROJECT_ID

Ejecuta el siguiente comando y crea el bucket de registros en el proyecto de usuario. Ten en cuenta que el nombre del bucket de registros debe ser el ID del proyecto de clúster de Google Cloud y no se puede cambiar ni modificar.

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

Ejecuta el siguiente comando para crear el receptor desde el espacio de nombres especificado en el proyecto de clúster de Google Cloud hasta el bucket del proyecto de Google Cloud de usuario. Ten en cuenta que puedes reducir el alcance de los registros, por ejemplo, para compartir solo un clúster de GKE individual o recursos de entrega específicos de Knative. Para ello, define valores log-filter adicionales.

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

Ejecuta los siguientes comandos y agrega el permiso de la cuenta de servicio del receptor de registros al bucket que creaste.

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 permisos de usuario con control de acceso basado en funciones (RBAC)

Anteriormente, usaste IAM y Grupos de Google para configurar permisos a fin de permitir que los usuarios accedan al proyecto de Google Cloud del clúster de GKE. Para permitir que los usuarios accedan a los recursos dentro del clúster de GKE, debes definir los permisos con el RBAC de Kubernetes.

Crea funciones de clúster

Después de definir y crear las siguientes funciones de clúster, puedes seguir usándolas en el futuro para agregar todos los usuarios posteriores del proyecto de clúster de Google Cloud.

Funciones de la IU

Esta función permite que los usuarios consulten todos los espacios de nombres. Se requiere a fin de encontrar los espacios de nombres a los que los usuarios tienen acceso para crear servicios /sdk/gcloud/reference/logging/sinks/create.

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

Con esta función, los usuarios pueden ver los servicios de entrega de Knative. Esto es necesario para enumerar los servicios en la IU de entrega de Knative.

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

Crea funciones de clúster

Solo uno de estos permisos es obligatorio. El primer permiso habilita a los usuarios a manipular cualquier recurso en el espacio de nombres. El segundo permiso permite un conjunto más limitado que consiste en solo crear servicios de entrega de Knative.

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

Si el permiso kubernetes-developer es demasiado permisivo, lo siguiente habilita a los usuarios a crear servicios de Knative en sus espacios de nombres y ver los otros recursos de 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

Crea espacio de nombres de usuario y asigna permisos

Ten en cuenta que se supone que realizaste la configuración mediante Grupos de Google para GKE. Esto se debe hacer para cada usuario.

export TENANT_GROUP=tenant-a@company.com

TENANT_GROUP debe ser parte de SECURITY_GROUP

Capacidad de ver todos los espacios de nombres

Para consultar el clúster de GKE, la mayoría de los usuarios tienen la capacidad de enumerar espacios de nombres. Por el momento, no hay un comando auth can-i que muestre espacios de nombres para los que sea posible realizar una acción. La única solución es enumerar los espacios de nombres y consultar cada uno de forma individual.

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

Puede enumerar los servicios de entrega de Knative.

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

Capacidad de manipular recursos en el espacio de nombres

Primero, crea el espacio de nombres:

kubectl create namespace $NAMESPACE

Si usas la función kubernetes-developer, usa este comando:

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

Si usas la función knative-developer, usa este comando:

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

Agrega la capacidad de un usuario de acceder a la dirección IP externa

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

Verifica la configuración

Puedes verificar que configuraste correctamente la función multiusuario para empresas abriendo el proyecto de usuario de Google Cloud en la entrega de Knative y, luego, implementando un servicio en un clúster de GKE.

Ir a la entrega de Knative

Felicitaciones, ahora el usuario puede interactuar con los servicios y los recursos en el espacio de nombres del clúster de GKE al que se le otorgó acceso.

Referencia de la arquitectura multiusuario