Isoler des charges de travail dans des pools de nœuds dédiés

Ce document explique comment améliorer la sécurité et la gestion de votre cluster Kubernetes en isolant les charges de travail de conteneurs dans des pools de nœuds dédiés dans Google Distributed Cloud (GDC) sous air gap. L'isolation de vos charges de travail vous permet de mieux contrôler vos pods et de réduire le risque d'attaques par élévation des privilèges dans votre cluster Kubernetes. Pour en savoir plus sur les avantages et les limites des pools de nœuds dédiés, consultez Présentation de l'isolation des nœuds.

L'isolation de vos charges de travail de conteneurs implique plusieurs workflows, dont les suivants :

  • Ajouter un rejet et un libellé à un pool de nœuds : appliquez un rejet et un libellé à un pool de nœuds afin qu'il repousse les pods, sauf s'ils sont spécifiquement libellés pour s'y exécuter.

  • Ajouter une tolérance et une règle d'affinité de nœuds : appliquez des tolérances et des règles à vos pods pour les forcer à s'exécuter uniquement sur le pool de nœuds désigné.

  • Vérifier que la séparation fonctionne : assurez-vous que vos pools de nœuds rejetés n'exécutent que les pods que vous avez libellés pour s'y exécuter.

Ces workflows sont destinés à des audiences telles que les administrateurs informatiques du groupe d'administrateurs de plate-forme, qui sont chargés de gérer les pools de nœuds d'un cluster Kubernetes, et les développeurs d'applications du groupe d'opérateurs d'applications, qui sont chargés de gérer les charges de travail de conteneurs. Pour en savoir plus, consultez Audiences pour la documentation GDC sous air gap.

Avant de commencer

Pour effectuer les tâches décrites dans ce document, vous devez demander les autorisations nécessaires et préparer votre environnement.

Demander des rôles IAM

Vous devez disposer de rôles spécifiques pour obtenir les autorisations nécessaires à l'isolation des charges de travail de conteneurs dans votre cluster Kubernetes. Les rôles dont vous avez besoin dépendent du fait que vous travailliez dans un cluster partagé au niveau de l'organisation ou dans un cluster standard au niveau du projet. Pour en savoir plus, consultez Configurations de cluster Kubernetes.

Rôles de cluster partagé

Contactez votre administrateur IAM de l'organisation pour demander les rôles suivants afin d'ajouter un rejet et un libellé à un pool de nœuds dans un cluster partagé :

  • Administrateur de cluster utilisateur (user-cluster-admin) : créez, supprimez, modifiez ou affichez les ressources d'un cluster partagé hébergé sur le serveur d'API de gestion. Ce rôle permet d'accéder aux pools de nœuds du cluster partagé.

  • Développeur de cluster utilisateur (user-cluster-developer) : créez, supprimez, modifiez ou affichez un cluster partagé. Ce rôle permet d'accéder aux API du plan de données hébergées dans le cluster partagé.

Ces rôles ne sont pas liés à un espace de noms.

Rôles de cluster standard

Contactez votre administrateur IAM de projet pour demander les rôles suivants afin d'ajouter un rejet et un libellé à un pool de nœuds dans un cluster standard :

  • Administrateur de cluster (cluster-admin) : créez, supprimez, modifiez ou affichez toutes les ressources d'un cluster standard. Ce rôle permet d'accéder aux API du plan de données hébergées dans le cluster standard qui régissent les ressources du cluster.

  • Développeur de cluster (cluster-developer) : créez, supprimez, modifiez ou affichez un cluster standard. Ce rôle permet d'accéder aux API du plan de données hébergées dans le cluster standard qui régissent le cluster.

  • Administrateur de cluster standard (standard-cluster-admin) : créez, supprimez, modifiez ou affichez les ressources d'un cluster standard hébergé sur le serveur d'API de gestion. Ce rôle permet d'accéder aux pools de nœuds du cluster standard.

Ces rôles sont liés à l'espace de noms de votre projet.

Préparer votre environnement

Pour exécuter des commandes sur un cluster Kubernetes à l'aide de l'API, assurez-vous de disposer des ressources suivantes :

  • Connectez-vous et générez le fichier kubeconfig pour le cluster Kubernetes.

  • Utilisez le chemin d'accès kubeconfig du cluster Kubernetes pour remplacer KUBERNETES_CLUSTER_KUBECONFIG dans ces instructions.

  • Connectez-vous et générez le fichier kubeconfig pour le serveur d'API de gestion.

  • Utilisez le chemin d'accès kubeconfig du serveur d'API de gestion pour remplacer MANAGEMENT_API_SERVER dans ces instructions.

  • Choisissez un nom spécifique pour le rejet de nœud et le libellé de nœud que vous souhaitez utiliser pour les pools de nœuds dédiés. Par exemple, workloadType=untrusted.

Ajouter un rejet et un libellé à un nouveau pool de nœuds

Lorsque vous appliquez un rejet ou un libellé à un nouveau pool de nœuds, tous les nœuds, y compris ceux ajoutés ultérieurement, reçoivent automatiquement les rejets et les libellés spécifiés. Vous ne pouvez pas supprimer un rejet ou un libellé d'un pool de nœuds une fois qu'il a été appliqué.

Pour ajouter un rejet et un libellé à un nouveau pool de nœuds, procédez comme suit :

  1. Modifiez directement la section nodePools de la ressource personnalisée Cluster lors de la création du pool de nœuds :

    nodePools:
      # Several lines of code are omitted here.
      - machineTypeName: n2-standard-2-gdc
        name: nodepool-1
        nodeCount: 3
        taints:
        - key: "TAINT_KEY"
          value: "TAINT_VALUE"
          effect: "TAINT_EFFECT"
        labels:
          LABEL_KEY: LABEL_VALUE
    

    Remplacez les éléments suivants :

    • TAINT_KEY : partie clé du rejet de la paire clé-valeur associée à un TAINT_EFFECT de planification. Par exemple, workloadType.
    • TAINT_VALUE : partie valeur du rejet de la paire clé-valeur associée à un TAINT_EFFECT de planification. Par exemple, untrusted.
    • TAINT_EFFECT : l'une des valeurs d'effet suivantes :
      • NoSchedule: les pods qui ne tolèrent pas ce rejet ne sont pas programmés sur le nœud ; les pods existants ne sont pas expulsés du nœud.
      • PreferNoSchedule: Kubernetes évite de programmer sur le nœud les pods qui ne tolèrent pas ce rejet.
      • NoExecute: si le pod est déjà en cours d'exécution sur le nœud, il est expulsé de celui-ci. Dans le cas contraire, il n'est pas programmé sur le nœud.
    • LABEL_KEY: LABEL_VALUE: paires clé/valeur pour les libellés de nœud, qui correspondent aux sélecteurs que vous spécifiez dans vos fichiers manifestes de charge de travail.
  2. Appliquez la ressource Cluster pour créer le pool de nœuds :

    kubectl apply -f cluster.yaml --kubeconfig MANAGEMENT_API_SERVER
    

    Remplacez MANAGEMENT_API_SERVER par le chemin d'accès kubeconfig du serveur d'API zonal où est hébergé le cluster Kubernetes.

Appliquer un rejet et un libellé à un pool de nœuds existant

Pour appliquer un rejet ou un libellé à un pool de nœuds existant, vous devez appliquer les modifications à chaque nœud existant. Vous ne pouvez pas mettre à jour dynamiquement les configurations de pool de nœuds.

Vous ne pouvez pas supprimer un rejet ou un libellé d'un pool de nœuds une fois qu'il a été appliqué.

Pour ajouter un rejet et un libellé à un pool de nœuds existant, procédez comme suit :

  1. Répertoriez les nœuds du pool de nœuds dédié :

    kubectl get node --kubeconfig KUBERNETES_CLUSTER_KUBECONFIG \
        -l baremetal.cluster.gke.io/node-pool=NODE_POOL_NAME
    

    Remplacez les variables suivantes :

    • KUBERNETES_CLUSTER_KUBECONFIG : chemin d'accès du fichier kubeconfig pour le cluster Kubernetes.
    • NODE_POOL_NAME: nom de votre pool de nœuds dédié.

    Notez l'ID de chaque nœud du pool de nœuds dans le résultat.

  2. Pour chaque nœud du pool de nœuds, appliquez les rejets :

    kubectl taint nodes NODE_ID \
        TAINT_KEY=TAINT_VALUE:TAINT_EFFECT \
        --kubeconfig KUBERNETES_CLUSTER_KUBECONFIG
    

    Remplacez les variables suivantes :

    • NODE_ID: ID du nœud de calcul dans le pool de nœuds dédié.
    • TAINT_KEY=TAINT_VALUE: paire clé-valeur associée à un TAINT_EFFECT. Par exemple, workloadType=untrusted.
    • TAINT_EFFECT: l'une des valeurs d'effet suivantes :
      • NoSchedule: les pods qui ne tolèrent pas ce rejet ne sont pas programmés sur le nœud ; les pods existants ne sont pas expulsés du nœud.
      • PreferNoSchedule: Kubernetes évite de programmer sur le nœud les pods qui ne tolèrent pas ce rejet.
      • NoExecute: si le pod est déjà en cours d'exécution sur le nœud, il est expulsé de celui-ci. Dans le cas contraire, il n'est pas programmé sur le nœud.
    • KUBERNETES_CLUSTER_KUBECONFIG : chemin d'accès du fichier kubeconfig pour le cluster Kubernetes.
  3. Pour chaque nœud du pool de nœuds, appliquez les libellés qui correspondent aux sélecteurs que vous définirez dans vos charges de travail de conteneurs :

    kubectl label NODE_ID \
        LABEL_KEY:LABEL_VALUE \
        --kubeconfig KUBERNETES_CLUSTER_KUBECONFIG
    

    Remplacez les variables suivantes :

    • NODE_ID: ID du nœud de calcul dans le pool de nœuds dédié.
    • LABEL_KEY:LABEL_VALUE : les paires clé/valeur pour les libellés de nœud, qui correspondent aux sélecteurs que vous spécifiez dans vos fichiers manifestes de charge de travail.
    • KUBERNETES_CLUSTER_KUBECONFIG : chemin d'accès du fichier kubeconfig pour le cluster Kubernetes.

Ajouter une tolérance et une règle d'affinité de nœuds

Une fois que vous avez ajouté un rejet au pool de nœuds dédié, aucune charge de travail ne peut y être programmée, à moins qu'elle ne dispose d'une tolérance correspondant au rejet que vous avez ajouté. Ajoutez la tolérance à la spécification de vos charges de travail afin de permettre la programmation de ces pods sur votre pool de nœuds rejeté.

Si vous avez attribué un libellé au pool de nœuds dédié, vous pouvez également ajouter une règle d'affinité de nœuds pour indiquer à GDC de ne planifier vos charges de travail que sur ce pool de nœuds.

Pour configurer votre charge de travail de conteneurs afin qu'elle s'exécute dans le pool de nœuds dédié, procédez comme suit :

  1. Ajoutez les sections suivantes à la section .spec.template.spec de votre fichier manifeste de charge de travail de conteneurs, par exemple une ressource personnalisée Deployment :

    tolerations:
    - key: TAINT_KEY
      operator: Equal
      value: TAINT_VALUE
      effect: TAINT_EFFECT
    affinity:
      nodeAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
          - matchExpressions:
            - key: LABEL_KEY
              operator: In
              values:
              - "LABEL_VALUE"
    

    Remplacez les éléments suivants :

    • TAINT_KEY: clé de rejet que vous avez appliquée à votre pool de nœuds dédié.
    • TAINT_VALUE: valeur de rejet que vous avez appliquée à votre pool de nœuds dédié.
    • TAINT_EFFECT: l'une des valeurs d'effet suivantes :
      • NoSchedule: les pods qui ne tolèrent pas ce rejet ne sont pas programmés sur le nœud ; les pods existants ne sont pas expulsés du nœud.
      • PreferNoSchedule: Kubernetes évite de programmer sur le nœud les pods qui ne tolèrent pas ce rejet.
      • NoExecute: si le pod est déjà en cours d'exécution sur le nœud, il est expulsé de celui-ci. Dans le cas contraire, il n'est pas programmé sur le nœud.
    • LABEL_KEY: clé d'étiquette de nœud que vous avez appliquée à votre pool de nœuds dédié.
    • LABEL_VALUE: valeur du libellé de nœud que vous avez appliquée à votre pool de nœuds dédié.

    Par exemple, la ressource Deployment suivante ajoute une tolérance pour le workloadType=untrusted:NoExecute et une règle d'affinité de nœuds pour le workloadType=untrusted libellé de nœud :

    kind: Deployment
    apiVersion: apps/v1
    metadata:
      name: my-app
      namespace: default
      labels:
        app: my-app
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: my-app
      template:
        metadata:
          labels:
            app: my-app
        spec:
          tolerations:
          - key: workloadType
            operator: Equal
            value: untrusted
            effect: NoExecute
          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: workloadType
                    operator: In
                    values:
                    - "untrusted"
          containers:
          - name: my-app
            image: harbor-1.org-1.zone1.google.gdc.test/harborproject/my-app
            ports:
            - containerPort: 80
          imagePullSecrets:
          - name: SECRET
    
  2. Mettez à jour votre charge de travail de conteneurs :

    kubectl apply -f deployment.yaml -n NAMESPACE \
        --kubeconfig KUBERNETES_CLUSTER_KUBECONFIG
    

    Remplacez les variables suivantes :

    • NAMESPACE: espace de noms de votre charge de travail de conteneurs. Pour les clusters partagés, il doit s'agir d'un espace de noms de projet. Pour les clusters standards, il peut s'agir de n'importe quel espace de noms.
    • KUBERNETES_CLUSTER_KUBECONFIG: chemin d'accès du fichier kubeconfig pour le cluster Kubernetes.

GDC recrée les pods concernés. La règle d'affinité de nœuds force l'application des pods sur le pool de nœuds dédié que vous avez créé. La tolérance ne permet de placer ces pods que sur les nœuds.

Vérifier que la séparation fonctionne

Vérifiez que les pods que vous avez désignés s'exécutent sur le pool de nœuds libellé.

  • Répertoriez les pods dans l'espace de noms donné :

    kubectl get pods -o=wide -n NAMESPACE \
        --kubeconfig KUBERNETES_CLUSTER_KUBECONFIG
    

    Remplacez les variables suivantes :

    • NAMESPACE: espace de noms de votre charge de travail de conteneurs. Pour les clusters partagés, il doit s'agir d'un espace de noms de projet. Pour les clusters standards, il peut s'agir de n'importe quel espace de noms.
    • KUBERNETES_CLUSTER_KUBECONFIG: chemin d'accès du fichier kubeconfig pour le cluster Kubernetes.

    La sortie ressemble à ceci :

    pod/kube-abc-12tyuj
    pod/kube-abc-39oplef
    pod/kube-abc-95rzkap
    

    Vérifiez que vos charges de travail s'exécutent dans le pool de nœuds dédié.

Étape suivante