Architecture mutualisée multiprojet pour Knative serving

Ce guide vous explique comment configurer Knative serving pour autoriser un ou plusieurs projets Google Cloud pour exécuter et gérer les charges de travail en cours d'exécution sur un cluster GKE dans un autre projet Google Cloud.

Avec Knative serving, un modèle d'exploitation courant est destiné à une équipe d'utiliser leur projet Google Cloud pour déployer et gérer des services exécutées dans des clusters GKE disparates appartenant à d'autres équipes projets Google Cloud. Cette fonctionnalité, appelée Architecture mutualisée, vous permet en tant qu'opérateur de plate-forme de personnaliser l'accès de vos équipes de développement et de le limiter à leurs propres services exécutés dans les divers environnements de vos organisations (par exemple, environnement de production ou préproduction).

Knative serving est spécifiquement adapté aux entreprises l'architecture mutualisée. Ce type d'architecture mutualisée active un projet Google Cloud de cluster afin de permettre l'accès à des ressources de leur cluster GKE. Le projet Google Cloud autorisé à accéder au projet Google Cloud du cluster est le projet Google Cloud locataire. Locataires de de cluster Google Cloud peuvent utiliser Knative serving pour accéder sont propriétaires des services et des ressources auxquels ils ont accès.

D'un point de vue conceptuel, configurer l'architecture mutualisée d'entreprise en quatre étapes Knative serving:

  1. Configurer l'accès du locataire au projet Google Cloud de cluster à l'aide d'un groupe Google Groupes Identity and Access Management.
  2. Mappez chaque projet Google Cloud locataire au projet Google Cloud du cluster.
  3. Acheminer les données de journaux du projet Google Cloud du cluster vers les projets Google Cloud locataires à l'aide de buckets de journaux d'évier.
  4. Définir les autorisations des locataires sur le cluster à l'aide du contrôle des accès basé sur les rôles.

Avant de commencer

L'opérateur de plate-forme responsable de la configuration de l'architecture mutualisée doit comprendre les exigences suivantes et les respecter :

Définir les variables d'environnement locales

Pour simplifier les commandes utilisées dans ce processus, définissez des variables d'environnement locales à la fois pour le projet Google Cloud de cluster et le projet Google Cloud locataire:

  1. Remplacez YOUR_CLUSTER_PROJECT_ID par l'ID du projet Google Cloud de cluster, puis exécutez la commande suivante:

    export CLUSTER_PROJECT_ID=YOUR_CLUSTER_PROJECT_ID
    
  2. Remplacez YOUR_TENANT_PROJECT_ID par l'ID du projet Google Cloud locataire, puis exécutez la commande suivante:

    export TENANT_PROJECT_ID=$YOUR_TENANT_PROJECT_ID
    
  3. Vérifiez vos variables d'environnement locales à l'aide des commandes suivantes :

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

L'ID du projet Google Cloud de votre cluster et l'ID du projet Google Cloud locataire sont désormais utilisés dans tous les éléments où $CLUSTER_PROJECT_ID et $TENANT_PROJECT_ID sont spécifiés.

Vérifier les autorisations IAM

Exécutez les commandes testIamPermissions suivantes : pour confirmer que vous disposez des autorisations IAM requises accéder aux ressources du projet Google Cloud de cluster ainsi qu'aux projets Google Cloud locataires.

Exécutez la commande suivante pour valider vos autorisations sur le projet Google Cloud du cluster:

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

Résultats attendus pour le projet Google Cloud de cluster:

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

Exécutez la commande suivante pour valider vos autorisations sur chaque projet Google Cloud locataire:

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

Résultats attendus pour chaque projet Google Cloud locataire:

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

Utiliser un groupe Google ainsi que la gestion de l'authentification et des accès pour configurer l'accès des locataires

Utilisez un groupe Google pour permettre aux locataires d'accéder au cluster GKE. Les autorisations IAM permettent aux locataires d'obtenir des identifiants, mais ils ne pourront effectuer aucune action au sein du cluster avant la configuration effective du contrôle d'accès basé sur les rôles Kubernetes, qui intervient dans une étape ultérieure.

Vous devez créer un groupe Google contenant tous les utilisateurs de votre projet Google Cloud locataire. Pour plus d'informations sur l'utilisation d'un groupe de sécurité, consultez la section Utiliser Google Groupes pour GKE.

Créez la variable d'environnement locale suivante pour représenter votre groupe Google :

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

Lecteur de cluster Kubernetes

Exécutez les commandes suivantes afin de permettre aux locataires d'obtenir des identifiants pour le cluster. Cela ne permet pas aux locataires de lire ou de manipuler des ressources sur le cluster GKE.

Documentation de référence sur IAM

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

Pour restreindre l'accès à un cluster spécifique, vous pouvez utiliser une condition 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"

Lecteur Monitoring

Exécutez la commande suivante afin d'autoriser les locataires à lire les métriques de surveillance.

Documentation de référence sur les rôles Monitoring

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

Mapper chaque projet Google Cloud locataire au projet Google Cloud du cluster

Vous utilisez des valeurs de paramètres de ressources pour mapper des projets Google Cloud locataires à un projet Google Cloud de cluster.

Le paramètre de ressource peut être configuré pour chaque projet Google Cloud locataire. peuvent être définis à n'importe quel niveau de la hiérarchie des dossiers. Il est plus facile de définir ce paramètre au niveau d'un dossier locataire unique, mais le définir au niveau de chaque projet locataire offre davantage de souplesse. Une fois la configuration terminée, chaque fois que les locataires consultent de Knative serving, les services associés un projet Google Cloud de cluster. Cela ne modifie pas les autorisations IAM sur le projet Google Cloud de cluster ou clusters GKE, il s'agit simplement d'un mappage entre un projet (ou dossier) locataire un projet Google Cloud de cluster.

  1. Activez l'API resourcesettings sur le projet Google Cloud locataire.

    gcloud services enable resourcesettings.googleapis.com \
      --project=$TENANT_PROJECT_ID
    
  2. Ajoutez les droits d'administrateur de l'organisation (roles/resourcesettings.admin) à votre ID utilisateur en exécutant la commande suivante :

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

    Remplacez YOUR_ORGANIZATION_ID par l'ID de votre organisation et YOUR_ADMIN_MEMBER_ID par votre ID utilisateur, par exemple user:my-email@my-domain.com.

  3. Choisissez l'une des méthodes suivantes pour définir le mappage.

    Vous pouvez définir la valeur du paramètre de ressource sur un dossier Google Cloud parent, si tous les projets et dossiers Google Cloud enfants utilisent cette même valeur.

Projets locataires

Définissez la valeur du paramètre de ressource pour chaque projet Google Cloud locataire:

  1. Obtenez le name du projet Google Cloud locataire et définissez-le dans un environnement local. :
    export TENANT_PROJECT_NUMBER=$(gcloud projects describe $TENANT_PROJECT_ID --format="value(projectNumber)")
  2. Créez un fichier de valeur de paramètre de ressource pour définir le mappage à partir du vers le projet Google Cloud de cluster. Plusieurs ID de projet Google Cloud de cluster peuvent être définies dans ce fichier et ajoutées à un projet Google Cloud à locataire unique.
    cat > value-file.json << EOF
    {
    "name": "projects/$TENANT_PROJECT_NUMBER/settings/cloudrun-multiTenancy/value",
    "value": {
      "stringSetValue": {
        "values": [ "projects/$CLUSTER_PROJECT_ID" ]
      }
    }
    }
    EOF
    
  3. Déployez les paramètres de ressource sur le projet Google Cloud locataire:
    gcloud resource-settings set-value cloudrun-multiTenancy --value-file value-file.json --project $TENANT_PROJECT_ID

Dossiers locataires

Définissez la valeur du paramètre de ressource d'un dossier locataire parent afin de définir cette à tous les projets et dossiers Google Cloud locataires enfants:

  1. Obtenez le number du dossier locataire et définissez-le sur un d'environnement:
    export TENANT_FOLDER_NUMBER=$TENANT_FOLDER_NUMBER
    
  2. Créez un fichier de valeur de paramètre de ressource pour définir le mappage à partir du vers le projet Google Cloud du cluster. Plusieurs ID de projet Google Cloud de cluster peuvent être définies dans ce fichier et ajoutées à un dossier locataire unique.
    cat > value-file.json << EOF
    {
    "name": "folders/$TENANT_FOLDER_NUMBER/settings/cloudrun-multiTenancy/value",
    "value": {
      "stringSetValue": {
        "values": [ "projects/$CLUSTER_PROJECT_ID" ]
      }
    }
    }
    EOF
    
  3. Déployez les paramètres de la ressource dans le dossier locataire:
    gcloud resource-settings set-value cloudrun-multiTenancy --value-file value-file.json --folder $TENANT_FOLDER_NUMBER

Configurer les buckets et récepteurs de journaux pour acheminer les données de journalisation

Pour chaque locataire, vous créez un bucket de journaux, un récepteur et les autorisations permettant d'acheminer les données de journaux du projet Google Cloud du cluster vers le projet Google Cloud locataire. Dans les étapes suivantes, tous les journaux de l'espace de noms du projet Google Cloud du cluster sont acheminés vers le bucket. Consultez l'ensemble ci-dessous pour découvrir comment limiter les journaux partagés.

Créez les variables d'environnement locales suivantes :

  • Spécifiez l'espace de noms du cluster GKE auquel vos locataires accèdent.
  • Nom du récepteur. Pour simplifier cette étape, le nom est une combinaison les variables d'environnement locales du projet Google Cloud de cluster et du projet Google Cloud locataire que vous avez précédemment créé. Vous pouvez modifier cette valeur.
export NAMESPACE=$NAMESPACE
export SINK_NAME=$CLUSTER_PROJECT_ID-$TENANT_PROJECT_ID

Exécutez la commande suivante afin de créer le bucket de journaux dans le projet locataire. Remarque que le nom du bucket de journaux doit correspondre à l'ID du projet Google Cloud du cluster et ne peut pas être modifié ou modifiées.

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

Exécutez la commande suivante pour créer le récepteur à partir de l'espace de noms spécifié dans la section le projet Google Cloud de cluster vers le bucket du projet Google Cloud locataire. Notez que vous pouvez réduire la portée les journaux, par exemple pour ne partager qu'un seul cluster GKE ou des ressources Knative serving spécifiques en définissant Valeurs log-filter.

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

Exécutez les commandes suivantes afin d'ajouter l'autorisation du compte de service du récepteur de journaux au bucket que vous avez créé précédemment.

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"

Configurer les autorisations des locataires à l'aide du contrôle d'accès basé sur les rôles (RBAC)

Vous avez déjà utilisé Google Groupes et IAM pour configurer pour permettre aux locataires d'accéder au projet Google Cloud cluster GKE. Pour autoriser des locataires à accéder aux ressources du cluster GKE, vous devez définir des autorisations à l'aide de Kubernetes RBAC.

Créer des rôles de cluster

Après avoir défini et créé les rôles de cluster suivants, vous pouvez continuer à utiliser pour ajouter tous les locataires suivants du projet Google Cloud de cluster.

Rôles pour l'interface utilisateur

Ce rôle permet aux locataires d'interroger tous les espaces de noms. Il sert à déterminer les espaces de noms auxquels les utilisateurs ont accès pour créer des services /sdk/gcloud/reference/logging/sinks/create.

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

Ce rôle permet aux locataires d'afficher les services Knative serving. Nécessaire pour répertorier les services dans l'interface utilisateur de Knative serving.

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

Créer des rôles de cluster

Une seule des autorisations suivantes est nécessaire. La première autorisation permet aux locataires de manipuler n'importe quelle ressource dans leur espace de noms. La deuxième autorisation permet un ensemble plus limité de créations Knative serving services.

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

Si l'autorisation kubernetes-developer est trop permissive, le code suivant permet aux locataires de créer des services Knative sur leurs espaces de noms et d'afficher les autres ressources 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

Créer un espace de noms locataire et attribuer des autorisations

Cette section présuppose que vous avez réalisé votre configuration à l'aide de Google Groupes pour GKE. Il est nécessaire d'effectuer cette opération pour chaque locataire.

export TENANT_GROUP=tenant-a@company.com

TENANT_GROUP doit faire partie de SECURITY_GROUP.

Rôle permettant d'afficher tous les espaces de noms

En matière d'interrogation du cluster GKE, tous les locataires ont au plus la possibilité de répertorier les espaces de noms. Il n'existe actuellement pas de commande auth can-i qui renverrait les espaces de noms sur lesquels une action donnée est autorisée. La seule solution consiste à répertorier l'ensemble des espaces de noms, puis à interroger chaque espace de noms individuellement.

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

Possibilité de lister les services Knative serving

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

Rôle permettant de manipuler les ressources dans l'espace de noms

Commencez par créer l'espace de noms :

kubectl create namespace $NAMESPACE

Si vous utilisez le rôle kubernetes-developer :

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

Si vous utilisez le rôle knative-developer :

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

Rôle permettant au locataire d'accéder à une adresse IP externe

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

Valider

Vous pouvez vérifier que vous avez correctement configuré l'architecture mutualisée d'entreprise en procédant comme suit : ouvrir le projet Google Cloud locataire dans Knative serving et déployer un service sur un cluster GKE.

Accéder à Knative serving

Félicitations, votre locataire peut désormais interagir avec les services et ressources figurant dans l'espace de noms du cluster GKE auquel il a accès.

Documentation de référence sur l'architecture mutualisée