Renforcer l'isolation d'une charge de travail avec GKE Sandbox

Cette page explique comment utiliser GKE Sandbox pour protéger le noyau hôte sur vos nœuds lorsque les conteneurs du pod exécutent du code inconnu ou non approuvé ou qu'ils ont besoin d'être davantage isolés du nœud.

Activer GKE Sandbox

Vous pouvez activer GKE Sandbox sur un nouveau cluster ou un cluster existant.

Avant de commencer

Avant de commencer, effectuez les tâches suivantes :

Configurez les paramètres gcloud par défaut à l'aide de l'une des méthodes suivantes :

  • Utilisez gcloud init pour suivre les instructions permettant de définir les paramètres par défaut.
  • Utilisez gcloud config pour définir individuellement l'ID, la zone et la région de votre projet.

Utiliser gcloud init

Si le message d'erreur One of [--zone, --region] must be supplied: Please specify location s'affiche, effectuez les tâches ci-dessous.

  1. Exécutez gcloud init et suivez les instructions :

    gcloud init

    Si vous utilisez SSH sur un serveur distant, utilisez l'option --console-only pour empêcher la commande d'ouvrir un navigateur :

    gcloud init --console-only
  2. Suivez les instructions pour autoriser gcloud à utiliser votre compte Google Cloud.
  3. Créez ou sélectionnez une configuration.
  4. Choisissez un projet Google Cloud.
  5. Choisissez une zone Compute Engine par défaut.

Utiliser gcloud config

  • Définissez votre ID de projet par défaut :
    gcloud config set project PROJECT_ID
  • Si vous utilisez des clusters zonaux, définissez votre zone de calcul par défaut :
    gcloud config set compute/zone COMPUTE_ZONE
  • Si vous utilisez des clusters régionaux, définissez votre région de calcul par défaut :
    gcloud config set compute/region COMPUTE_REGION
  • Mettez à jour gcloud vers la dernière version :
    gcloud components update
  • Pour le plan de contrôle et les nœuds du cluster, GKE Sandbox nécessite GKE version 1.13.5-gke.15 ou une version ultérieure.
  • Assurez-vous que la commande gcloud est de version 243.0.0 ou ultérieure.

Sur un nouveau cluster

Pour activer GKE Sandbox, vous configurez un pool de nœuds. Le pool de nœuds par défaut (le premier pool de nœuds de votre cluster, créé lors de la création du cluster) ne peut pas utiliser GKE Sandbox. Pour activer GKE Sandbox lors de la création du cluster, vous devez ajouter un deuxième pool de nœuds lorsque vous créez le cluster.

Console

Pour afficher vos clusters, accédez au menu Google Kubernetes Engine de Cloud Console.

  1. Accédez au menu Google Kubernetes Engine de Cloud Console.

    Accéder au menu Google Kubernetes Engine

  2. Cliquez sur Créer.

  3. Facultatif, mais recommandé : Dans le volet de navigation, sous Cluster, cliquez sur Fonctionnalités et activez la suite d’opérations Cloud pour GKE, afin que les messages gVisor soient journalisés.

  4. Cliquez sur  Ajouter un pool de nœuds.

  5. Dans le volet de navigation, sous Pools de nœuds, développez le nouveau pool de nœuds, puis cliquez sur Nœuds.

  6. Configurez les paramètres suivants pour le pool de nœuds :

    1. Dans la liste déroulante Type d'image, sélectionnez Container-Optimized OS avec Containerd (cos_containerd).
    2. Sous Configuration de la machine, sélectionnez une série et un type de machine.

  7. Dans le volet de navigation, sous le nom du pool de nœuds que vous configurez, cliquez sur Sécurité, puis cochez la case Activer l'isolation en bac à sable avec gVisor.

  8. Continuez à configurer le cluster et les pools de nœuds selon vos besoins.

  9. Cliquez sur Create (Créer).

gcloud

GKE Sandbox ne peut pas être activé pour le pool de nœuds par défaut, et il n'est pas possible de créer d'autres pools de nœuds en même temps que vous créez un cluster à l'aide de la commande gcloud. Au lieu de cela, créez votre cluster comme vous le feriez normalement. Il est facultatif mais recommandé d'activer Stackdriver Logging et Stackdriver Monitoring, en ajoutant l'option --enable-stackdriver-kubernetes. Les messages gVisor sont consignés.

Ensuite, utilisez la commande gcloud container node-pools create et définissez l'option --sandbox sur type=gvisor. Remplacez les valeurs entre crochets par les vôtres.

gcloud container node-pools create node-pool-name \
  --cluster=cluster-name \
  --node-version=node-version \
  --machine-type=machine-type \
  --image-type=cos_containerd \
  --sandbox type=gvisor \

Avant 1.18.4-gke.1300, le paramètre RuntimeClass gvisor est instancié lors de la création du nœud. Avant de programmer des charges de travail sur le nœud, vérifiez la présence du paramètre RuntimeClass gvisor à l'aide de la commande suivante :

kubectl get runtimeclasses
NAME     AGE
gvisor   19s

Si vous exécutez une version antérieure à 1.17.9-gke.1500 ou une version 1.18 antérieure à 1.18.1-gke.600, vous devez également attendre que le paramètre gvisor.config.common-webhooks.networking.gke.io soit instancié. Pour le vérifier, exécutez la commande suivante :

kubectl get mutatingwebhookconfiguration gvisor.config.common-webhooks.networking.gke.io
NAME                                              CREATED AT
gvisor.config.common-webhooks.networking.gke.io   2020-04-06T17:07:17Z

Sur un cluster existant

Pour activer GKE Sandbox sur un cluster existant, vous pouvez ajouter un nouveau pool de nœuds et activer la fonctionnalité pour ce pool.

Console

Pour créer un pool de nœuds avec GKE Sandbox activé :

  1. Accédez au menu Google Kubernetes Engine de Cloud Console.

    Accéder au menu Google Kubernetes Engine

  2. Cliquez sur le nom du cluster que vous souhaitez modifier.

  3. Cliquez sur  Ajouter un pool de nœuds.

  4. Configurez la page Détails du pool de nœuds selon vos besoins.

  5. Dans le volet de navigation, cliquez sur Nœuds et configurez les paramètres suivants :

    1. Dans la liste déroulante Type d'image, sélectionnez Container-Optimized OS avec Containerd (cos_containerd).
    2. Sous Configuration de la machine, sélectionnez une série et un type de machine.

  6. Dans le volet de navigation, cliquez sur Sécurité, puis cochez la case Activer l'isolation en bac à sable avec gVisor.

  7. Cliquez sur Create (Créer).

gcloud

Pour créer un pool de nœuds avec GKE Sandbox activé, exécutez une commande telle que celle-ci :

gcloud container node-pools create node-pool-name \
  --cluster=cluster-name \
  --machine-type=machine-type \
  --image-type=cos_containerd \
  --sandbox type=gvisor

Avant 1.18.4-gke.1300, le paramètre RuntimeClass gvisor est instancié lors de la création du nœud. Avant de programmer des charges de travail sur le nœud, vérifiez la présence du paramètre RuntimeClass gvisor à l'aide de la commande suivante :

kubectl get runtimeclasses
NAME     AGE
gvisor   19s

Si vous exécutez une version antérieure à 1.17.9-gke.1500 ou une version 1.18 antérieure à 1.18.1-gke.600, vous devez également attendre que le paramètre gvisor.config.common-webhooks.networking.gke.io soit instancié. Pour le vérifier, exécutez la commande suivante :

kubectl get mutatingwebhookconfiguration gvisor.config.common-webhooks.networking.gke.io
NAME                                              CREATED AT
gvisor.config.common-webhooks.networking.gke.io   2020-04-06T17:07:17Z

Facultatif : Activer la suite d'opérations Cloud pour GKE

Il est facultatif mais recommandé d'activer la suite d'opérations Cloud pour GKE sur le cluster afin que les messages gVisor soient journalisés. La suite d'opérations Cloud pour GKE est activée par défaut pour les nouveaux clusters.

Vous pouvez utiliser Google Cloud Console pour activer ces fonctionnalités sur un cluster existant.

  1. Accédez au menu Google Kubernetes Engine de Cloud Console.

    Accéder au menu Google Kubernetes Engine

  2. Cliquez sur le nom du cluster que vous souhaitez modifier.

  3. Sous Fonctionnalités, dans le champ Suite d'opérations Cloud pour GKE, cliquez sur Modifier la suite d'opérations Cloud pour GKE.

  4. Cochez la case Activer la suite des opérations Cloud pour GKE.

  5. Dans la liste déroulante, sélectionnez Journalisation et surveillance du système et de la charge de travail.

  6. Cliquez sur Save Changes (Enregistrer les modifications).

Utiliser GKE Sandbox

Exécuter une application dans un bac à sable

Pour forcer un déploiement à s'exécuter sur un nœud sur lequel GKE Sandbox est activé, définissez le paramètre spec.template.spec.runtimeClassName sur gvisor, comme indiqué dans le fichier manifeste de déploiement ci-dessous :

# httpd.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd
  labels:
    app: httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpd
  template:
    metadata:
      labels:
        app: httpd
    spec:
      runtimeClassName: gvisor
      containers:
      - name: httpd
        image: httpd

Pour créer le déploiement, utilisez la commande kubectl create :

kubectl create -f httpd.yaml

Le pod est déployé sur un nœud d'un pool de nœuds sur lequel GKE Sandbox est activé. Pour vérifier le déploiement, utilisez la commande suivante pour trouver le nœud sur lequel le pod est déployé :

kubectl get pods

Le résultat est semblable à :

NAME                    READY   STATUS    RESTARTS   AGE
httpd-db5899bc9-dk7lk   1/1     Running   0          24s

Recherchez le nom du pod dans le résultat, puis exécutez la commande suivante pour vérifier sa valeur pour RuntimeClass :

kubectl get pods pod-name -o jsonpath='{.spec.runtimeClassName}'

Le résultat est :

gvisor

Vous pouvez également répertorier la valeur RuntimeClass de chaque pod et rechercher ceux qui affichent la valeur gvisor :

kubectl get pods -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.runtimeClassName}\n{end}'

Le résultat est le suivant :

pod-name: gvisor

Cette méthode permettant de vérifier que le pod s'exécute dans un bac à sable est fiable, car elle ne repose sur aucune donnée contenue dans le bac à sable. Tout ce qui provient du bac à sable est considéré comme à risque, car il peut contenir des éléments défaillants ou malveillants.

Exécution d'un pod standard avec des pods en bac à sable

Après avoir activé GKE Sandbox sur un pool de nœuds, vous pouvez exécuter des applications approuvées sur ces nœuds sans utiliser de bac à sable, à l'aide des paramètres de rejet et de tolérance de nœud. Ces pods sont appelés "pods standards" pour les distinguer des pods en bac à sable.

Les pods standards, tout comme les pods en bac à sable, ne peuvent pas accéder aux autres services Google Cloud ni aux métadonnées du cluster. Cette protection fait partie de la configuration du nœud. Si vos pods standards ou en bac à sable nécessitent un accès aux services Google Cloud, utilisez Workload Identity.

GKE Sandbox ajoute les étiquettes et les rejets suivants aux nœuds qui peuvent exécuter des pods en bac à sable :

labels:
  sandbox.gke.io/runtime: gvisor
taints:
- effect: NoSchedule
  key: sandbox.gke.io/runtime
  value: gvisor

En plus des paramètres d'affinité et de tolérance des nœuds dans votre fichier manifeste de pod, GKE Sandbox applique les paramètres d'affinité et de tolérance suivants à tous les pods dont la valeur RuntimeClass est définie sur gvisor :

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: sandbox.gke.io/runtime
          operator: In
          values:
          - gvisor
tolerations:
  - effect: NoSchedule
    key: sandbox.gke.io/runtime
    operator: Equal
    value: gvisor

Pour programmer un pod standard sur un nœud avec GKE Sandbox activé, appliquez manuellement les paramètres d'affinité et de tolérance de nœud ci-dessus dans votre fichier manifeste de pod.

  • Si le pod peut s'exécuter sur des nœuds avec GKE Sandbox activé, ajoutez la tolérance.
  • Si votre pod doit s'exécuter sur des nœuds avec GKE Sandbox activé, ajoutez à la fois l'affinité et la tolérance de nœud.

Le fichier manifeste suivant modifie le fichier manifeste utilisé dans la section Exécuter une application dans un bac à sable afin qu'il s'exécute comme un pod standard sur un nœud contenant des pods en bac à sable. Ici, la valeur runtimeClass est supprimée et les paramètres de rejet et de tolérance ci-dessus sont ajoutés.

# httpd-no-sandbox.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd-no-sandbox
  labels:
    app: httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpd
  template:
    metadata:
      labels:
        app: httpd
    spec:
      containers:
      - name: httpd
        image: httpd
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: sandbox.gke.io/runtime
                operator: In
                values:
                - gvisor
      tolerations:
        - effect: NoSchedule
          key: sandbox.gke.io/runtime
          operator: Equal
          value: gvisor

Tout d'abord, vérifiez que le déploiement ne s'exécute pas dans un bac à sable :

kubectl get pods -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.runtimeClassName}\n{end}'

Le résultat est semblable à :

httpd-db5899bc9-dk7lk: gvisor
httpd-no-sandbox-5bf87996c6-cfmmd:

Le déploiement httpd créé précédemment s'exécute dans un bac à sable, car son runtimeClass est gvisor. Le déploiement httpd-no-sandbox n'affiche pas de valeur runtimeClass. Il ne s'exécute donc pas dans un bac à sable.

Ensuite, vérifiez que le déploiement hors bac à sable s'exécute sur un nœud avec GKE Sandbox à l'aide de la commande suivante :

kubectl get pod -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.nodeName}\n{end}'

Le nom du pool de nœuds est intégré dans la valeur de nodeName. Vérifiez que le pod s'exécute sur un nœud dans un pool de nœuds avec GKE Sandbox activé.

Valider la protection des métadonnées

Pour valider la déclaration selon laquelle les métadonnées sont protégées des nœuds pouvant exécuter des pods en bac à sable, vous pouvez effectuer le test suivant :

  1. Créez un déploiement en bac à sable à partir du fichier manifeste suivant, en utilisant kubectl apply -f. Cette fonction utilise l'image fedora, qui inclut la commande curl. Le pod exécute la commande /bin/sleep pour s'assurer que le déploiement s'exécute pendant 10 000 secondes.

    # sandbox-metadata-test.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: fedora
      labels:
        app: fedora
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: fedora
      template:
        metadata:
          labels:
            app: fedora
        spec:
          runtimeClassName: gvisor
          containers:
          - name: fedora
            image: fedora
            command: ["/bin/sleep","10000"]
    
  2. Récupérez le nom du pod en utilisant kubectl get pods, puis connectez-vous au pod de manière interactive à l'aide de kubectl exec.

    kubectl exec -it pod-name /bin/sh
    

    Vous êtes connecté à un conteneur s'exécutant dans le pod, dans une session /bin/sh.

  3. Dans la session interactive, essayez d'accéder à une URL qui renvoie des métadonnées de cluster :

    curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/kube-env" -H "Metadata-Flavor: Google"
    

    La commande se bloque et finit par expirer, car les paquets sont ignorés.

  4. Appuyez sur Ctrl+C pour terminer la commande curl et saisissez exit pour vous déconnecter du pod.

  5. Supprimez la ligne RuntimeClass du fichier manifeste YAML et redéployez le pod à l'aide de kubectl apply -f filename. Le pod en bac à sable est arrêté et recréé sur un nœud sans GKE Sandbox.

  6. Obtenez le nouveau nom du pod, connectez-vous à l'aide de kubectl exec et exécutez à nouveau la commande curl. Cette fois, les résultats sont renvoyés. Cet exemple de sortie est tronqué.

    ALLOCATE_NODE_CIDRS: "true"
    API_SERVER_TEST_LOG_LEVEL: --v=3
    AUTOSCALER_ENV_VARS: kube_reserved=cpu=60m,memory=960Mi,ephemeral-storage=41Gi;...
    ...
    

    Saisissez exit pour vous déconnecter du pod.

  7. Supprimez le déploiement :

    kubectl delete deployment fedora
    

Désactiver GKE Sandbox

Il n'est actuellement pas possible de mettre à jour un pool de nœuds pour désactiver GKE Sandbox. Pour désactiver GKE Sandbox sur un pool de nœuds existant, vous pouvez effectuer l'une des opérations suivantes :

Étape suivante