Cette page explique comment isoler vos charges de travail de conteneurs dans des pools de nœuds dédiés dans Google Distributed Cloud (GDC) air-gapped pour vous donner plus de contrôle sur vos pods. L'isolation des charges de travail présente certains avantages, tels que :
- Réduction du risque d'attaques par élévation des privilèges dans votre cluster Kubernetes.
- Contrôle accru sur les pods qui nécessitent des ressources supplémentaires.
Dans ce cas, envisagez d'isoler vos charges de travail de conteneurs pour plus de contrôle et d'optimisation.
Pourquoi dois-je isoler mes charges de travail ?
Il n'est pas obligatoire d'isoler vos charges de travail dans des pools de nœuds dédiés, mais cela peut être une mesure prudente pour éviter d'éventuels problèmes. Toutefois, sachez que la gestion de pools de nœuds dédiés nécessite une surveillance plus poussée et est souvent inutile.
Les clusters Kubernetes utilisent des charges de travail privilégiées gérées par GDC pour activer des fonctionnalités de clusters spécifiques, telles que la collecte de métriques. Ces charges de travail disposent d'autorisations spéciales pour s'exécuter correctement dans le cluster.
Les charges de travail que vous déployez sur vos nœuds peuvent être compromises par une entité malveillante. Si vous exécutez ces charges de travail avec des charges de travail privilégiées gérées par GDC, un pirate informatique qui s'échappe avec un conteneur compromis peut utiliser les identifiants de la charge de travail privilégiée sur le nœud pour élever les privilèges dans votre cluster.
Les pools de nœuds dédiés sont également utiles lorsque vous devez planifier des pods nécessitant plus de ressources que d'autres, par exemple plus de mémoire ou plus d'espace disque local.
Vous pouvez utiliser les mécanismes suivants pour planifier vos charges de travail sur un pool de nœuds dédié :
- Taints de nœuds : https://cloud.google.com/kubernetes-engine/docs/how-to/node-taints
- Affinité de nœud : https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/
Un rejet de nœud indique à votre cluster Kubernetes d'éviter de planifier des charges de travail sans tolérance correspondante, telles que les charges de travail gérées par GDC, sur ces nœuds. L'affinité de nœud sur vos propres charges de travail indique au cluster de planifier vos pods sur les nœuds dédiés.
Limites de l'isolation des nœuds
Les pirates informatiques peuvent toujours lancer des attaques par déni de service (DoS) à partir du nœud compromis.
Les nœuds compromis peuvent toujours lire de nombreuses ressources, y compris tous les pods et espaces de noms du cluster.
Les nœuds compromis peuvent accéder aux secrets et aux identifiants utilisés par chaque pod exécuté sur ce nœud.
L'utilisation d'un pool de nœuds distinct pour isoler les charges de travail peut avoir un impact sur la rentabilité, l'autoscaling et l'utilisation des ressources.
Les nœuds compromis peuvent toujours contourner les règles de réseau de sortie.
Certaines charges de travail gérées par GDC doivent s'exécuter sur chaque nœud de votre cluster et être configurées pour tolérer tous les rejets.
Si vous déployez des ressources
DaemonSet
disposant de privilèges élevés et pouvant tolérer les rejets, ces pods peuvent constituer un moyen d'augmenter les privilèges à partir d'un nœud compromis.
Fonctionnement de l'isolation des nœuds
Pour implémenter l'isolation des nœuds pour vos charges de travail, vous devez procéder comme suit :
Ajoutez un rejet et un libellé au pool de nœuds pour vos charges de travail.
Mettez à jour vos charges de travail avec la tolérance et la règle d'affinité de nœud correspondantes.
Dans ce guide, nous partons du principe que vous disposez d'un pool de nœuds dans votre cluster. L'utilisation de l'affinité des nœuds en plus des rejets de nœuds n'est pas obligatoire, mais nous vous recommandons de l'utiliser, car vous bénéficiez d'un meilleur contrôle sur la planification.
Avant de commencer
Avant de commencer, effectuez les tâches suivantes :
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
.Si nécessaire, demandez à l'administrateur IAM de votre organisation de vous attribuer le rôle Développeur de cluster utilisateur (
user-cluster-developer
), qui n'est pas lié à un espace de noms.
Ajouter un rejet et un libellé à un pool de nœuds
Lorsque vous appliquez un rejet ou un libellé à un nouveau pool de nœuds, il est appliqué automatiquement à tous les nœuds, y compris ceux ajoutés ultérieurement.
Pour ajouter un rejet et un libellé à un nouveau pool de nœuds, procédez comme suit :
Modifiez directement la section
nodePools
de la ressource personnaliséeCluster
lorsque vous créez le pool de nœuds :nodePools: ... - machineTypeName: n2-standard-2-gdc name: nodepool-1 nodeCount: 3 taints: TAINT_KEY=TAINT_VALUE:TAINT_EFFECT labels: LABEL_KEY=LABEL_VALUE
Remplacez les éléments suivants :
TAINT_KEY=TAINT_VALUE
: paire clé-valeur associée à unTAINT_EFFECT
de planification. 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 les pods qui ne tolèrent pas ce rejet sur le nœud.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.
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ù le cluster Kubernetes est hébergé. Si vous n'avez pas encore généré de fichier kubeconfig pour le serveur d'API dans la zone cible, consultez Se connecter pour en savoir plus.
Ajouter un rejet et un libellé à un pool de nœuds existant
Pour appliquer un taint 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.
Pour ajouter un rejet et un libellé à un pool de nœuds existant, procédez comme suit :
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 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 à partir du résultat.
Pour chaque nœud du pool de nœuds, appliquez les taints :
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 à unTAINT_EFFECT
de planification. 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 les pods qui ne tolèrent pas ce rejet sur le nœud.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 kubeconfig pour le cluster Kubernetes.
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 conteneur :
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
: 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 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 conteneur afin qu'elle s'exécute dans le pool de nœuds dédié, procédez comme suit :
Ajoutez les sections suivantes à la section
.spec.template.spec
de votre charge de travail de conteneur :kind: Deployment apiVersion: apps/v1 ... spec: ... template: spec: 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 les pods qui ne tolèrent pas ce rejet sur le nœud.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é du libellé 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 au rejetworkloadType=untrusted:NoExecute
et une règle d'affinité de nœud pour le libellé de nœudworkloadType=untrusted
: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
Mettez à jour votre déploiement :
kubectl apply -f deployment.yaml -n NAMESPACE \ --kubeconfig KUBERNETES_CLUSTER_KUBECONFIG
Remplacez les variables suivantes :
NAMESPACE
: espace de noms du projet de votre charge de travail de conteneur.KUBERNETES_CLUSTER_KUBECONFIG
: chemin d'accès 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
Pour vérifier que la planification fonctionne correctement, exécutez la commande suivante et vérifiez si vos charges de travail se trouvent dans le pool de nœuds dédié :
kubectl get pods -o=wide -n NAMESPACE \
--kubeconfig KUBERNETES_CLUSTER_KUBECONFIG
Recommandations et bonnes pratiques
Après avoir configuré l'isolation des nœuds, nous vous recommandons d'effectuer les opérations suivantes :
- Lorsque vous créez des pools de nœuds, empêchez la plupart des charges de travail gérées par GDC de s'exécuter sur ces nœuds en ajoutant un rejet à ces pools.
- Chaque fois que vous déployez de nouvelles charges de travail sur votre cluster, par exemple lors de l'installation d'outils tiers, vérifiez les autorisations requises par les pods. Dans la mesure du possible, évitez de déployer des charges de travail qui utilisent des autorisations avec privilèges élevés sur des nœuds partagés.