Migrer depuis OpenShift vers GKE Enterprise : migrer les contraintes de contexte de sécurité OpenShift vers GKE Enterprise

Last reviewed 2022-01-24 UTC

Ce document vous aide à planifier la migration des règles de sécurité depuis les contraintes de contexte de sécurité (SCC) OpenShift, définies sur un cluster OpenShift source, vers un cluster GKE cible. La mise en œuvre utilise des contraintes Policy Controller pour définir les règles migrées sur le cluster cible.

Dans ce document, nous partons du principe que vous connaissez comment Migrer des conteneurs vers Google Cloud : migrer OpenShift vers GKE Enterprise. Nous considérons également que vous connaissez OpenShift et les contraintes de contexte de sécurité, et que vous avez accès à un cluster OpenShift source et à un cluster GKE cible.

Ce document fait partie d'une série d'articles sur la migration vers Google Cloud. Pour obtenir une présentation de la série, consultez la page Migration vers Google Cloud : choisir votre chemin de migration.

Ce document fait partie d'une série qui traite de la migration de conteneurs vers Google Cloud :

Ce document est utile si vous envisagez de migrer des contraintes de contexte de sécurité OpenShift vers GKE Enterprise. Ce document est également utile si vous évaluez l'opportunité d'effectuer une migration et si vous souhaitez découvrir à quoi elle pourrait ressembler.

Ce document s'appuie sur les concepts abordés dans les pages Migration vers Google Cloud : premiers pas, Migrer des conteneurs vers Google Cloud : migrer Kubernetes vers GKE, Migrer des conteneurs vers Google Cloud : migrer OpenShift vers GKE Enterprise et Bonnes pratiques de mise en réseau GKE. Vous trouverez des liens vers ces documents, le cas échéant.

Contraintes de contexte de sécurité OpenShift

Les contraintes de contexte de sécurité sont des ressources spécifiques à OpenShift qui permettent de définir des règles pour les pods afin de spécifier les actions qu'un pod peut effectuer et les ressources auxquelles il peut accéder sur les nœuds. Lorsque vous effectuez une requête API pour créer un pod, les contraintes de contexte de sécurité évaluent les requêtes de pod en termes de droits de processus par rapport à un ensemble de règles définies via la contrainte de contexte de sécurité. Les contraintes de contexte de sécurité évaluent les requêtes pour autoriser ou interdire l'exécution des pods conformément aux stratégies configurées. Pour en savoir plus sur les contraintes de contexte de sécurité OpenShift, consultez la page Gérer les contraintes de contexte de sécurité.

Contraintes de contexte de sécurité OpenShift par défaut

Les clusters OpenShift 4.x contiennent un ensemble de contraintes de contexte de sécurité par défaut, décrites dans l'article de blog de Red Hat Gérer les contraintes de contexte de sécurité dans OpenShift.

Config Sync et Policy Controller.

Cette section décrit les outils Config Sync et Policy Controller. Cette section fournit des liens vers la documentation et des conseils pertinents pour configurer Policy Controller pour effectuer les tâches de migration décrites plus loin dans ce document.

Config Sync

Config Sync vous permet d'utiliser un dépôt commun compatible avec Git pour définir de manière centralisée la configuration d'une ressource s'appliquant à tout cluster Kubernetes géré par GKE Enterprise. Vous allez appliquer cette configuration à plusieurs clusters.

Policy Controller

Policy Controller est un contrôleur d'admission dynamique Kubernetes qui vérifie, audite et applique la conformité pour vos clusters avec des règles définies de manière centralisée. Policy Controller est basé sur le projet Open Source Open Policy Agent (OPA) Gatekeeper.

Configuration de Config Sync et Policy Controller

Pour préparer la mise en œuvre de règles de sécurité qui reflètent les contraintes de contexte de sécurité OpenShift, activez les composants Config Sync et Policy Controller pour chacun de vos clusters cibles. Cette section explique comment configurer ces composants. La section Migrer des contraintes de contexte de sécurité OpenShift plus loin dans ce document explique comment utiliser les modèles de contraintes de Policy Controller pour mettre en œuvre les stratégies de sécurité.

Lorsque vous configurez le composant Policy Controller, il est recommandé de spécifier dans le champ Espaces de noms exemptés les espaces de noms liés au système et qui n'exécutent pas de pods d'application. L'exemption des espaces de noms liés au système vous permet d'éviter le blocage de tout pod système nécessitant des privilèges élevés. Parmi les espaces de noms liés au système sur un cluster GKE figurent ceux ci-après :

  • kube-system
  • kube-public
  • gke-connect
  • gke-system
  • config-management-system
  • config-management-monitoring
  • gatekeeper-system
  • istio-system
  • cnrm-system
  • knative-serving
  • monitoring-system

Après avoir configuré Policy Controller avec les exceptions précédentes, excluez les espaces de noms de l'application des contraintes en ajoutant le libellé admission.gatekeeper.sh/ignore=true à chaque espace de noms. Si vous n'ajoutez pas le libellé à chaque espace de noms, les pods système (et donc l'ensemble de votre cluster) peuvent être affectés par des règles restrictives.

Migrer des contraintes de contexte de sécurité OpenShift vers les contraintes Policy Controller

Cette section explique comment exporter des contraintes de contexte de sécurité depuis votre cluster OpenShift et configurer les contraintes Policy Controller pour GKE Enterprise cibles pour qu'elles correspondent aux règles requises. Cette section décrit également certaines différences entre les contraintes de contexte de sécurité et les contraintes Policy Controller afin de pouvoir planifier votre migration en conséquence.

Évaluer les contraintes de contexte de sécurité OpenShift

Pour exporter une liste et la configuration des contraintes de contexte de sécurité installées dans votre cluster OpenShift, vous pouvez utiliser les commandes ci-dessous :

  1. Obtenez la liste de toutes les contraintes de contexte de sécurité :

    oc get scc
    
  2. Exportez la configuration de chaque contrainte de contexte de sécurité :

    oc get scc SCC_NAME > SCC_NAME.yaml
    

    Remplacez SCC_NAME par le nom de la contrainte de contexte de sécurité pour laquelle vous souhaitez exporter la configuration.

Après avoir exporté la configuration, vous pouvez l'analyser et utiliser le tableau de la section Mapper les contraintes de contexte de sécurité OpenShift pour configurer les contraintes Policy Controller correspondant aux exigences de sécurité de votre application.

Mapper les contraintes de contexte de sécurité OpenShift aux modèles de contraintes Policy Controller

Le tableau suivant spécifie les contraintes et les paramètres de Policy Controller qui correspondent aux champs SCC OpenShift et à leurs valeurs possibles. Utilisez ce tableau pour configurer des contraintes cibles Policy Controller qui répondent aux exigences de sécurité des applications mises en œuvre via les contrainte SCC OpenShift dans l'environnement source. La section Exemple de migration de bout en bout, plus loin dans ce document, fournit un exemple d'utilisation des informations du tableau.

Champ des contraintes de contexte de sécurité OpenShift Type / valeurs possibles Modèle de contrainte Policy Controller Spécification de la contrainte Policy Controller
allowPrivilegedContainer: Booléen K8sPSPPrivilegedContainer Empêche les conteneurs privilégiés, le cas échéant.
allowHostIPC: Booléen K8sPSPHostNamespace Empêche l'accès à l'espace de noms pid et ipc, le cas échéant.
allowHostPID: Booléen K8sPSPHostNamespace Empêche l'accès à l'espace de noms pid et ipc, le cas échéant.
allowHostNetwork: Booléen K8sPSPHostNetworkingPorts Comporte un paramètre booléen pour empêcher l'accès au réseau hôte, et peut définir une plage pour les ports hôtes accessibles.
allowHostPorts: Booléen K8sPSPHostNetworkingPorts Comporte un paramètre booléen pour empêcher l'accès au réseau hôte, et peut définir une plage pour les ports hôtes accessibles.
readOnlyRootFilesystem: Booléen K8sPSPReadOnlyRootFilesystem Permet d'installer le système de fichiers racine du conteneur en lecture seule, le cas échéant.
allowPrivilegeEscalation: true Booléen K8sPSPAllowPrivilegeEscalationContainer Empêche les pods avec le contexte de sécurité AllowPrivilegeEscalation défini sur true, le cas échéant.
allowHostDirVolumePlugin: Booléen K8sPSPVolumeTypes Comporte un paramètre permettant de définir la liste des types de volumes autorisés (comme dans les contraintes de contexte de sécurité), y compris le répertoire hôte.
volumes: Liste de type array avec le type de volumes autorisés K8sPSPVolumeTypes Comporte un paramètre permettant de définir la liste des types de volumes autorisés (comme dans les contraintes de contexte de sécurité), y compris le répertoire hôte.
allowedCapabilities: Liste de type array des fonctionnalités Linux pouvant être demandées. K8sPSPCapabilities Comporte des paramètres permettant de définir les fonctionnalités Linux pouvant être demandées (allowedCapabilities) et celles qui sont interdites (requiredDropCapabilites).

Il ne peut pas être utilisé pour ajouter ou supprimer directement les fonctionnalités répertoriées, comme dans defaultAddCapabilities: et requiredDropCapabilities: dans les contraintes de contexte de sécurité OpenShift.

defaultAddCapabilities: Liste de type array des fonctionnalités Linux devant être ajoutées à chaque conteneur. K8sPSPCapabilities Comporte des paramètres permettant de définir les fonctionnalités Linux pouvant être demandées (allowedCapabilities) et celles qui sont interdites (requiredDropCapabilites).

Il ne peut pas être utilisé pour ajouter ou supprimer directement les fonctionnalités répertoriées, comme dans defaultAddCapabilities: et requiredDropCapabilities: dans les contraintes de contexte de sécurité OpenShift.

requiredDropCapabilities: Liste de type array des fonctionnalités Linux qui sont automatiquement supprimées du pod ou du conteneur. K8sPSPCapabilities Comporte des paramètres permettant de définir les fonctionnalités Linux pouvant être demandées (allowedCapabilities) et celles qui sont interdites (requiredDropCapabilites).

Il ne peut pas être utilisé pour ajouter ou supprimer directement les fonctionnalités répertoriées, comme dans defaultAddCapabilities: et requiredDropCapabilities: dans les contraintes de contexte de sécurité OpenShift.

fsGroup: Comporte un type: key qui peut être l'un des éléments suivants :
  • MustRunAs : nécessite la spécification d'au moins une plage si vous n'utilisez pas de valeurs préallouées.
  • RunAsAny : permet de spécifier n'importe quel ID fsGroup.
K8sPSPAllowedUsers Permet de définir des règles ayant une fonction semblable à celle de type: key dans les contraintes de contexte de sécurité et de id pour les champs runAsUser, runAsGroup, supplementalGroups et les paramètres fsGroup.

Peut être utilisé pour définir des plages autorisées pour les utilisateurs, les groupes, les groupes supplémentaires ou les groupes FS, mais pas pour définir l'ID utilisateur directement dans le pod, comme cela peut être fait dans les contraintes de contexte de sécurité OpenShift.

runAsUser: Comporte un type: key qui peut être l'un des éléments suivants :
  • MustRunAs : nécessite une configuration runAsUser.
  • MustRunAsRange : nécessite la définition des valeurs minimales et maximales si vous n'utilisez pas des valeurs préallouées de l'espace de noms.
  • MustRunAsNonRoot : nécessite que le pod soit envoyé avec une valeur runAsUser non nulle ou que la directive USER soit définie dans l'image.
  • RunAsAny : autorise la spécification de runAsUser.
K8sPSPAllowedUsers Permet de définir des règles ayant une fonction semblable à celle de type: key dans les contraintes de contexte de sécurité et de id pour les champs runAsUser, runAsGroup, supplementalGroups et les paramètres fsGroup.

Peut être utilisé pour définir des plages autorisées pour les utilisateurs, les groupes, les groupes supplémentaires ou les groupes FS, mais pas pour définir l'ID utilisateur directement dans le pod, comme cela peut être fait dans les contraintes de contexte de sécurité OpenShift.

supplementalGroups: Comporte un type: key qui peut être l'un des éléments suivants :
  • MustRunAs : nécessite la spécification d'au moins une plage si vous n'utilisez pas de valeurs préallouées de l'espace de noms.
  • RunAsAny : permet de spécifier n'importe quel supplementalGroups.
K8sPSPAllowedUsers Permet de définir des règles ayant une fonction semblable à celle de type: key dans les contraintes de contexte de sécurité et de id pour les champs runAsUser, runAsGroup, supplementalGroups et les paramètres fsGroup.

Peut être utilisé pour définir des plages autorisées pour les utilisateurs, les groupes, les groupes supplémentaires ou les groupes FS, mais pas pour définir l'ID utilisateur directement dans le pod, comme cela peut être fait dans les contraintes de contexte de sécurité OpenShift.

seLinuxContext: Comporte un type: key qui peut être l'un des éléments suivants :
  • MustRunAs : nécessite la configuration de seLinuxOptions si vous n'utilisez pas des valeurs préallouées de l'espace de noms.
  • RunAsAny : autorise la spécification de seLinuxOptions.
K8sPSPSELinuxV2 Comporte un paramètre allowedSELinuxOptions dans lequel vous pouvez définir le niveau, le rôle, le type et l'utilisateur autorisés par la configuration seLinuxOptions.

Différences entre les contraintes de contexte de sécurité OpenShift et Policy Controller

Cette section décrit certaines différences entre les contraintes Policy Controller et les contraintes SCC OpenShift. Tenez compte de ces différences avant d'utiliser le tableau précédent pour déployer des contraintes sur votre environnement cible.

Application des contraintes aux ressources

Vous pouvez attribuer des contraintes de contexte de sécurité OpenShift aux utilisateurs et aux groupes à l'aide de la spécification users: ou group: présente dans l'objet de la contrainte de contexte de sécurité. Avec OpenShift 4.x et versions ultérieures, vous pouvez également attribuer des contraintes des contexte de sécurité aux utilisateurs ou aux groupes à l'aide du contrôle des accès basé sur les rôles (RBAC). Les contraintes de contexte de sécurité comportent également un champ priority: qui permet de classer les contraintes de contexte de sécurité appliquées à un pod.

Les contraintes Policy Controller sont appliquées aux clusters cibles, aux espaces de noms ou aux pods en utilisant des sélecteurs de ressources spécifiques dans la contrainte, au lieu de cibler l'utilisateur ou le compte de service. Pour en savoir plus, consultez la documentation sur Policy Controller. L'utilisation de sélecteurs de ressources spécifiques permet de garantir que le pod se comporte de la même manière si un utilisateur à faible privilèges l'exécute à l'aide d'un outil de déploiement ou si un cluster d'administrateur le lance à partir de la ligne de commande.

Les contraintes Policy Controller sont également compatibles avec un mode de simulation, qui vous permet de tester les règles et d'auditer les violations avant de les appliquer. Ce mode vous permet d'éviter tout impact sur les charges de travail existantes, tandis que les contraintes de contexte de sécurité sont toujours appliquées, le cas échéant.

Mutation de pod des contraintes de contexte de sécurité utilisant des valeurs préallouées dans les espaces de noms OpenShift

Dans les contraintes SCC OpenShift, vous pouvez modifier le contexte de sécurité associé à chaque pod auquel la contrainte SCC est appliquée, à l'aide d'un ID spécifique provenant d'une plage préallouée fournie par les annotations dans les espaces de noms. Pour ce faire, utilisez les champs RunAsUser, fsGroup, supplementalGroups et seLinuxContext avec un type de stratégie MustRunAs ou MustRunAsRange.

Par exemple, supposons qu'une contrainte de contexte de sécurité restricted comporte un champ RunAsUser avec un type de stratégie MustRunAsRange sans plage définie dans la contrainte de contexte de sécurité. Dans ce scénario, chaque pod auquel s'applique la contrainte de contexte de sécurité obtient un ID RunAsUser de la plage spécifiée dans l'annotation openshift.io/sa.scc.uid-range dans l'espace de noms du pod.

Les contraintes Policy Controller, associées aux fonctionnalités de mutation, permettent de procéder à la validation et à la mutation des pods. Cependant, les contraintes n'utilisent pas d'annotations dans les espaces de noms pour fournir des valeurs pour les contextes de sécurité des pods. La section suivante, Exemple de migration de bout en bout, montre comment vos équipes de diffusion d'applications doivent configurer explicitement des contextes de sécurité sur les pods, afin de respecter les contraintes appliquant des restrictions semblables à celles listées précédemment.

Exemple de migration de bout en bout

Cette section fournit un exemple de fichier manifeste cible qui inclut toutes les contraintes et tous les mutateurs Policy Controller dont vous avez besoin pour mapper les contraintes de contexte de sécurité OpenShift par défaut suivantes sur votre cluster GKE cible :

  • privileged
  • anyuid
  • nonroot
  • restricted

En fonction de l'espace de noms dans lequel un pod s'exécute, le pod obtient différentes contraintes Policy Controller lorsque vous mappez les règles des contraintes de contexte de sécurité définies dans un environnement OpenShift source :

  • Les charges de travail qui nécessitent l'accès avec le plus de privilèges, telles que l'exécution en mode privilégié ou l'accès à n'importe quelle ressource hôte, doivent s'exécuter dans l'un des espaces de noms exempts définis dans la configuration de Policy Controller.

    Aucune contrainte n'est appliquée aux espaces de noms exemptés. Les charges de travail qui disposent de ce niveau d'accès le plus élevé sont généralement des composants système ou toute charge de travail à laquelle la contrainte SCC privilégiée a été appliquée dans l'environnement OpenShift source.

  • Tous les pods créés dans un espace de noms non exempté se voient appliquer les contraintes les plus restrictives. Ces contraintes refusent l'accès à toutes les fonctionnalités de l'hôte et obligent les pods à s'exécuter avec un UID correspondant à une plage spécifique. Cette configuration correspond aux règles appliquées par la contrainte SCC restricted d'OpenShift. Les exceptions à cette configuration sont les suivantes :

    • Les pods créés dans un espace de noms portant le libellé security=anyuid se voient appliquer les contraintes restrictives précédentes, mais sont autorisés à s'exécuter avec n'importe quel UID et n'importe quel GID. Cela correspond aux contraintes de la SCC anyuid sur OpenShift.
    • Les pods créés dans un espace de noms portant le libellé security=nonroot se voient appliquer les contraintes restrictives précédentes. Toutefois, les pods sont autorisés à s'exécuter avec n'importe quel UID non racine. Cela correspond aux contraintes de la SCC nonroot sur OpenShift.

Exemple de fichier manifeste cible

Voici un exemple de fichier manifeste unique qui inclut un ensemble de contraintes et de mutateurs Policy Controller correspondant au comportement décrit dans l'exemple précédent de migration de bout en bout. Nous vous recommandons de vérifier et d'ajuster les contraintes ou leur champ d'application dans cet exemple, selon les besoins de votre entreprise.

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPHostNamespace
metadata:
  name: psp-host-namespace
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPHostNetworkingPorts
metadata:
  name: psp-host-network-ports
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
  parameters:
    hostNetwork: false
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
  name: psp-privileged-container
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
---
apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: restricted-capabilities
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  match:
    scope: Namespaced
    kinds:
    - apiGroups: ["*"]
      kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: NotIn
          key: security
          values: ["anyuid"]
  location: "spec.containers[name:*].securityContext.capabilities.drop"
  parameters:
    assign:
      value: ["KILL","MKNOD","SYS_CHROOT"]
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPCapabilities
metadata:
  name: restricted-capabilities
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: NotIn
          key: security
          values: ["anyuid"]
  parameters:
    requiredDropCapabilities: ["KILL","MKNOD","SYS_CHROOT"]
---
apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: anyuid-capabilities
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  match:
    scope: Namespaced
    kinds:
    - apiGroups: ["*"]
      kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: In
          key: security
          values: ["anyuid"]
  location: "spec.containers[name:*].securityContext.capabilities.drop"
  parameters:
    assign:
      value: ["MKNOD"]
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPCapabilities
metadata:
  name: anyuid-capabilities
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: In
          key: security
          values: ["anyuid"]
  parameters:
    requiredDropCapabilities: ["MKNOD"]
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPAllowedUsers
metadata:
  name: restricted-users-and-groups
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: NotIn
          key: security
          values: ["anyuid","nonroot"]
  parameters:
    runAsUser:
      rule: MustRunAs # MustRunAsNonRoot # RunAsAny
      ranges:
        - min: 1000
          max: 2000
    fsGroup:
      rule: MustRunAs # MayRunAs # RunAsAny
      ranges:
        - min: 1000
          max: 2000
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPAllowedUsers
metadata:
  name: nonroot-users-and-groups
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: In
          key: security
          values: ["nonroot"]
  parameters:
    runAsUser:
      rule: MustRunAsNonRoot
    fsGroup:
      rule: MustRunAsNonRoot
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPVolumeTypes
metadata:
  name: psp-volume-types
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
  parameters:
    volumes:
      - configMap
      - downwardAPI
      - emptyDir
      - nfs
      - persistentVolumeClaim
      - projected
      - secret

La contrainte restricted-users-and-groups de l'exemple de fichier manifeste utilise le modèle K8sPSPAllowedUsers pour définir explicitement un exemple de plage allant de 1 000 à 2 000 pour les paramètres runAsUser: et fsGroup:. Tous les pods qui ne sont pas configurés pour utiliser un ID de cette plage pour runAsUser: et fsGroup: sont bloqués.

GKE Enterprise et Kubernetes n'utilisent pas d'annotations d'espaces de noms pour effectuer automatiquement des mutations sur les pods avec un ID d'utilisateur ou de groupe spécifique. Par conséquent, pour limiter la plage UID comme dans l'exemple précédent, vos équipes de diffusion d'applications doivent définir explicitement un UID conforme sur le pod créé, ou bien vous devez supprimer complètement la contrainte afin d'autoriser n"importe quel ID.

Voici un exemple de fichier manifeste de pod conforme aux contraintes précédentes dans tout espace de noms dans lequel vous le créez (le fichier manifeste est conforme à la contrainte de contexte de sécurité restricted) :

apiVersion: v1
kind: Pod
metadata:
  name: restricted-pod-example
spec:
  securityContext:
    runAsUser: 1000
    fsGroup: 1100
  volumes:
  - name: sec-ctx-vol
    emptyDir: {}
  containers:
  - name: sec-ctx-demo
    image: busybox
    command: [ "sh", "-c", "sleep 1h" ]
    volumeMounts:
    - name: sec-ctx-vol
      mountPath: /data/demo

Étapes suivantes

  • Découvrez des architectures de référence, des schémas et des bonnes pratiques concernant Google Cloud. Consultez notre Centre d'architecture cloud.