Créer des contraintes

Cette page vous explique comment définir les contraintes du service Policy Controller.

Policy Controller vous permet d'appliquer des règles pour un cluster Kubernetes en définissant un ou plusieurs objets de contrainte. Une fois qu'une contrainte est installée, les requêtes adressées au serveur d'API sont vérifiées en fonction de la contrainte et sont rejetées si elles ne sont pas conformes. Les ressources non conformes préexistantes sont signalées au moment de l'audit.

Chaque contrainte s'accompagne d'un modèle de contrainte qui définit le schéma et la logique de la contrainte. Les modèles de contraintes peuvent provenir de Google, de tiers ou vous pouvez écrire les vôtres. Pour en savoir plus sur la création de modèles, consultez la page Écrire un modèle de contrainte.

Avant de commencer

Utiliser la bibliothèque de modèles de contraintes

Lorsque vous définissez une contrainte, vous spécifiez le modèle de contrainte correspondant. Une bibliothèque de modèles de contraintes courants développés par Google est installée par défaut, et de nombreuses organisations n'ont pas besoin de créer de modèles de contraintes personnalisés directement dans Rego. Les modèles de contraintes fournis par Google ont le libellé configmanagement.gke.io/configmanagement.

Pour répertorier les contraintes, utilisez la commande suivante :

kubectl get constrainttemplates \
    -l="configmanagement.gke.io/configmanagement=config-management"

Pour décrire un modèle de contrainte et vérifier ses paramètres requis, utilisez la commande suivante :

kubectl describe constrainttemplate CONSTRAINT_TEMPLATE_NAME

Vous pouvez également afficher tous les modèles de contraintes dans la bibliothèque.

Définir une contrainte

Vous définissez une contrainte à l'aide d'un fichier YAML. Vous n'avez pas besoin de comprendre Rego, ni de savoir écrire dans ce langage. Au lieu de cela, vous utilisez une contrainte qui invoque un modèle de contrainte et lui fournit des paramètres spécifiques.

Si vous utilisez un dépôt structuré, nous vous recommandons de créer vos contraintes dans le répertoire cluster/.

Les contraintes comportent les champs suivants :

  • Le champ kind en minuscule correspond au nom d'un modèle de contrainte.
  • Le champ metadata.name correspond au nom de la contrainte.
  • Le champ match définit les objets auxquels la contrainte s'applique. Toutes les conditions spécifiées doivent être mises en correspondance avant qu'un objet soit soumis au champ d'application d'une contrainte. Les conditions match sont définies par les sous-champs suivants :
    • kinds sont les types de ressources auxquels la contrainte s'applique, déterminés par deux champs : apiGroups (liste de groupes d'API Kubernetes correspondants) et kinds (liste de types correspondants). "*" correspond à tout. Si au moins une entrée apiGroup et une entrée kind correspondent, la condition kinds est satisfaite.
    • namespaces est une liste de noms d'espaces de noms auxquels l'objet peut appartenir. L'objet doit appartenir au moins à l'un de ces espaces de noms. Les ressources d'espace de noms sont traitées comme si elles appartenaient à elles-mêmes.
    • excludedNamespaces est une liste d'espaces de noms auxquels l'objet ne peut pas appartenir.
    • labelSelector est un sélecteur de libellé Kubernetes que l'objet doit satisfaire.
    • namespaceSelector est un sélecteur de libellé sur l'espace de noms auquel appartient l'objet. Si l'espace de noms ne satisfait pas l'objet, il ne correspondra pas. Les ressources d'espace de noms sont traitées comme si elles appartenaient à elles-mêmes.
  • Le champ parameters définit les arguments de la contrainte, en fonction des attentes du modèle de contrainte.

La contrainte suivante, appelée ns-must-have-geo, appelle un modèle de contrainte appelé K8sRequiredLabels, qui est inclus dans la bibliothèque de modèles de contraintes fournie par Google. La contrainte définit les paramètres que le modèle de contrainte utilise pour évaluer si le libellé geo est défini sur une valeur pour les espaces de noms.

# ns-must-have-geo.yaml

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: ns-must-have-geo
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    labels:
      - key: "geo"

Pour créer la contrainte, utilisez kubectl apply -f :

kubectl apply -f ns-must-have-geo.yaml

Auditer une contrainte

Si la contrainte est configurée et installée correctement, son champ status.byPod[].enforced est défini sur true, que la contrainte soit configurée pour appliquer ou pour auditer uniquement la contrainte.

Les contraintes sont appliquées par défaut et la violation d'une contrainte empêche une opération de cluster donnée. Vous pouvez définir le paramètre spec.enforcementAction d'une contrainte sur dryrun pour signaler les violations dans le champ status.violations sans empêcher l'opération.

Pour en savoir plus sur l'audit, consultez la page Effectuer un audit à l'aide de contraintes.

Mises en garde concernant la synchronisation de contraintes

Gardez à l'esprit les mises en garde suivantes lors de la synchronisation des contraintes.

Cohérence à terme

Vous pouvez effectuer un commit des contraintes sur le dépôt et limiter leurs effets à l'aide des objets ClusterSelectors ou NamespaceSelectors. Étant donné que la synchronisation est cohérente à terme, gardez à l'esprit les mises en garde suivantes :

  • Si une opération de cluster déclenche une contrainte dont le paramètre NamespaceSelector fait référence à un espace de noms qui n'a pas été synchronisé, la contrainte est appliquée et l'opération ne peut aboutir. En d'autres termes, un espace de noms manquant provoque une erreur "fails closed".
  • Si vous modifiez les libellés d'un espace de noms, le cache peut contenir des données obsolètes pendant une courte période.

Minimisez la nécessité de renommer un espace de noms ou de modifier ses libellés, et testez les contraintes qui affectent un espace de noms renommé ou dont le libellé a été modifié pour vous assurer que tout fonctionne comme prévu.

Configurer Policy Controller pour les contraintes référentielles

Avant de pouvoir activer les contraintes référentielles, vous devez créer une configuration qui indique à Policy Controller les types d'objets à surveiller, tels que les espaces de noms.

Enregistrez le fichier manifeste YAML suivant dans un fichier et appliquez-le avec kubectl. Le fichier manifeste configure Policy Controller pour surveiller les objets Namespace et Ingress. Créez une entrée avec group, version et kind sous spec.sync.syncOnly, avec les valeurs pour chaque type d'objet que vous souhaitez surveiller.

apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
  name: config
  namespace: "gatekeeper-system"
spec:
  sync:
    syncOnly:
      - group: ""
        version: "v1"
        kind: "Namespace"
      - group: "extensions"
        version: "v1beta1"
        kind: "Ingress"

Activer des contraintes référentielles

Une contrainte référentielle fait référence à un autre objet dans sa définition. Par exemple, vous pouvez créer une contrainte nécessitant que les objets Ingress d'un cluster aient des noms d'hôte uniques. La contrainte est référentielle si son modèle de contrainte contient la chaîne data.inventory dans son Rego.

Les contraintes référentielles sont désactivées par défaut dans Policy Controller. Les contraintes référentielles ne sont garanties que pour être cohérentes à terme, ce qui engendre certains risques :

  • Sur un serveur d'API surchargé, le contenu du cache de Policy Controller peut devenir obsolète, provoquant l'échec ("fail open") d'une contrainte référentielle, ce qui signifie que l'action d'application semble fonctionner alors que ce n'est pas le cas. Par exemple, vous pouvez créer des objets Ingress avec des noms d'hôte en double trop rapidement pour que le contrôleur d'admission soit en mesure de détecter les doublons.

  • L'ordre dans lequel les contraintes sont installées et l'ordre dans lequel le cache est mis à jour sont tous deux aléatoires.

Si vous comprenez ces risques et souhaitez toujours autoriser les contraintes référentielles, définissez policyController.referentialRulesEnabled sur true dans l'objet de l'opérateur :

apiVersion: configmanagement.gke.io/v1
kind: ConfigManagement
metadata:
  name: config-management
  namespace: config-management-system
spec:
  clusterName: my-cluster
  channel: dev
  policyController:
    enabled: true
    referentialRulesEnabled: true

Répertorier toutes les contraintes

Pour répertorier toutes les contraintes installées sur un cluster, exécutez la commande suivante :

kubectl get constraint

Supprimer une contrainte

Pour rechercher toutes les contraintes qui utilisent un modèle de contrainte, exécutez la commande suivante pour répertorier tous les objets ayant le même paramètre kind que le champ metadata.name du modèle de contrainte :

kubectl get CONSTRAINT_TEMPLATE_NAME

Pour supprimer une contrainte, spécifiez ses paramètres kind et name :

kubectl delete CONSTRAINT_TEMPLATE_NAME CONSTRAINT_NAME

Si vous souhaitez supprimer le modèle de contrainte utilisé par la contrainte, notez le paramètre kind de la contrainte.

Lorsque vous supprimez une contrainte, elle cesse d'être appliquée dès que le serveur d'API la marque comme supprimée.

Supprimer tous les modèles de contraintes

Définissez spec.policyController.templateLibraryInstalled sur false. Cela empêche l'opérateur de réinstaller automatiquement la bibliothèque.

Pour supprimer tous les modèles de contraintes et toutes les contraintes, exécutez la commande suivante :

kubectl delete constrainttemplate --all

Restaurer la bibliothèque de modèles de contraintes

Si vous avez désactivé la bibliothèque de modèles de contraintes ou désinstallé tous les modèles de contraintes, vous pouvez la restaurer en définissant spec.policyController.templateLibraryInstalled sur true dans la configuration de l'opérateur.

Dépannage

Erreur lors de la création d'un modèle de contrainte

Si l'erreur porte la mention disallowed ref, vérifiez que vous avez activé les contraintes référentielles. Par exemple, si vous utilisez data.inventory dans un modèle de contrainte sans activer des contraintes référentielles au préalable, l'erreur ressemble à ceci :

admission webhook "validation.gatekeeper.sh" denied the request: check refs failed on module {templates["admission.k8s.gatekeeper.sh"]["MyTemplate"]}: disallowed ref data.inventory...

Étapes suivantes