Valider Kubernetes YAML par rapport aux meilleures pratiques et politiques

Noter. trad.: Avec le nombre croissant de configurations YAML pour les environnements K8, le besoin de leur vérification automatisée devient de plus en plus urgent. L'auteur de cette revue a non seulement sélectionné les solutions existantes pour cette tâche, mais a également utilisé le déploiement comme exemple pour voir comment elles fonctionnent. Cela s'est avéré très instructif pour ceux qui s'intéressent à ce sujet.

Valider Kubernetes YAML par rapport aux meilleures pratiques et politiques

TL; DR: Cet article compare six outils statiques pour valider et évaluer les fichiers YAML Kubernetes par rapport aux meilleures pratiques et exigences.

Les charges de travail Kubernetes sont généralement définies sous la forme de documents YAML. L'un des problèmes de YAML est la difficulté de spécifier des contraintes ou des relations entre les fichiers manifestes.

Que se passe-t-il si nous devons nous assurer que toutes les images déployées sur le cluster proviennent d'un registre approuvé ?

Comment puis-je empêcher les déploiements qui n'ont pas de PodDisruptionBudgets d'être envoyés au cluster ?

L'intégration de tests statiques vous permet d'identifier les erreurs et les violations de politique au stade du développement. Cela augmente la garantie que les définitions de ressources sont correctes et sécurisées, et rend plus probable que les charges de travail de production suivront les meilleures pratiques.

L’écosystème d’inspection de fichiers YAML statique Kubernetes peut être divisé dans les catégories suivantes :

  • Validateurs d'API. Les outils de cette catégorie vérifient le manifeste YAML par rapport aux exigences du serveur API Kubernetes.
  • Testeurs prêts. Les outils de cette catégorie sont accompagnés de tests prêts à l'emploi pour la sécurité, le respect des bonnes pratiques, etc.
  • Validateurs personnalisés. Les représentants de cette catégorie vous permettent de créer des tests personnalisés dans différents langages, par exemple Rego et Javascript.

Dans cet article, nous allons décrire et comparer six outils différents :

  1. Kubeval;
  2. score kube ;
  3. config-lint ;
  4. cuivre;
  5. concours;
  6. polaris.

Eh bien, commençons !

Vérification des déploiements

Avant de commencer à comparer les outils, créons un contexte sur lequel les tester.

Le manifeste ci-dessous contient un certain nombre d’erreurs et de non-respect des bonnes pratiques : combien pouvez-vous en trouver ?

apiVersion: apps/v1
kind: Deployment
metadata:
  name: http-echo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: http-echo
  template:
    metadata:
      labels:
        app: http-echo
    spec:
      containers:
      - name: http-echo
        image: hashicorp/http-echo
        args: ["-text", "hello-world"]
        ports:
        - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: http-echo
spec:
  ports:
  - port: 5678
    protocol: TCP
    targetPort: 5678
  selector:
    app: http-echo

(base-valid.yaml)

Nous utiliserons ce YAML pour comparer différents outils.

Le manifeste ci-dessus base-valid.yaml et d'autres manifestes de cet article peuvent être trouvés dans Dépôts Git.

Le manifeste décrit une application Web dont la tâche principale est de répondre par un message « Hello World » sur le port 5678. Elle peut être déployée avec la commande suivante :

kubectl apply -f hello-world.yaml

Et donc - vérifiez le travail :

kubectl port-forward svc/http-echo 8080:5678

Allez maintenant à http://localhost:8080 et confirmez que l'application fonctionne. Mais suit-il les meilleures pratiques ? Allons vérifier.

1. Kubéval

Au cœur Kubeval L'idée est que toute interaction avec Kubernetes se fait via son API REST. En d’autres termes, vous pouvez utiliser un schéma API pour vérifier si un YAML donné s’y conforme. Regardons un exemple.

Instructions d'installation kubeval sont disponibles sur le site Web du projet.

Au moment de la rédaction de l'article original, la version 0.15.0 était disponible.

Une fois installé, alimentons-le avec le manifeste ci-dessus :

$ kubeval base-valid.yaml
PASS - base-valid.yaml contains a valid Deployment (http-echo)
PASS - base-valid.yaml contains a valid Service (http-echo)

En cas de succès, Kubeval se terminera avec le code de sortie 0. Vous pouvez le vérifier comme suit :

$ echo $?
0

Essayons maintenant Kubeval avec un autre manifeste :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: http-echo
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: http-echo
    spec:
      containers:
      - name: http-echo
        image: hashicorp/http-echo
        args: ["-text", "hello-world"]
        ports:
        - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: http-echo
spec:
  ports:
  - port: 5678
    protocol: TCP
    targetPort: 5678
  selector:
    app: http-echo

(kubeval-invalid.yaml)

Pouvez-vous repérer le problème à l’oeil nu ? Lançons :

$ kubeval kubeval-invalid.yaml
WARN - kubeval-invalid.yaml contains an invalid Deployment (http-echo) - selector: selector is required
PASS - kubeval-invalid.yaml contains a valid Service (http-echo)

# проверим код возврата
$ echo $?
1

La ressource n'est pas en cours de vérification.

Déploiements utilisant la version API apps/v1, doit inclure un sélecteur qui correspond à l'étiquette du pod. Le manifeste ci-dessus n'inclut pas le sélecteur, donc kubeval a signalé une erreur et s'est terminé avec un code différent de zéro.

Je me demande ce qui se passera si je le fais kubectl apply -f avec ce manifeste ?

Eh bien, essayons :

$ kubectl apply -f kubeval-invalid.yaml
error: error validating "kubeval-invalid.yaml": error validating data: ValidationError(Deployment.spec):
missing required field "selector" in io.k8s.api.apps.v1.DeploymentSpec; if you choose to ignore these errors,
turn validation off with --validate=false

C'est exactement l'erreur contre laquelle Kubeval a mis en garde. Vous pouvez résoudre ce problème en ajoutant un sélecteur :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: http-echo
spec:
  replicas: 2
  selector:          # !!!
    matchLabels:     # !!!
      app: http-echo # !!!
  template:
    metadata:
      labels:
        app: http-echo
    spec:
      containers:
      - name: http-echo
        image: hashicorp/http-echo
        args: ["-text", "hello-world"]
        ports:
        - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: http-echo
spec:
  ports:
  - port: 5678
    protocol: TCP
    targetPort: 5678
  selector:
    app: http-echo

(base-valid.yaml)

L'avantage d'outils comme Kubeval est que de telles erreurs peuvent être détectées dès le début du cycle de déploiement.

De plus, ces vérifications ne nécessitent pas d'accès au cluster ; elles peuvent être effectuées hors ligne.

Par défaut, Kubeval vérifie les ressources par rapport au dernier schéma de l'API Kubernetes. Cependant, dans la plupart des cas, vous devrez peut-être vérifier par rapport à une version spécifique de Kubernetes. Cela peut être fait en utilisant le drapeau --kubernetes-version:

$ kubeval --kubernetes-version 1.16.1 base-valid.yaml

Veuillez noter que la version doit être spécifiée au format Major.Minor.Patch.

Pour une liste des versions pour lesquelles la vérification est prise en charge, veuillez vous référer à Schéma JSON sur GitHub, que Kubeval utilise pour la validation. Si vous devez exécuter Kubeval hors ligne, téléchargez les schémas et spécifiez leur emplacement local à l'aide du drapeau --schema-location.

En plus des fichiers YAML individuels, Kubeval peut également fonctionner avec des répertoires et stdin.

De plus, Kubeval s'intègre facilement au pipeline CI. Ceux qui souhaitent exécuter des tests avant d'envoyer des manifestes au cluster seront heureux de savoir que Kubeval prend en charge trois formats de sortie :

  1. Texte brut ;
  2. JSON ;
  3. Testez tout le protocole (TAP).

Et n'importe lequel des formats peut être utilisé pour une analyse plus approfondie de la sortie afin de générer un résumé des résultats du type souhaité.

L'un des inconvénients de Kubeval est qu'il ne peut actuellement pas vérifier la conformité avec les définitions de ressources personnalisées (CRD). Cependant, il est possible de configurer Kubeval ignore les.

Kubeval est un excellent outil pour vérifier et évaluer les ressources ; Il convient toutefois de souligner que la réussite du test ne garantit pas que la ressource est conforme aux meilleures pratiques.

Par exemple, en utilisant la balise latest dans un conteneur ne suit pas les meilleures pratiques. Cependant, Kubeval ne considère pas cela comme une erreur et ne la signale pas. Autrement dit, la vérification de ce YAML se terminera sans avertissement.

Mais que se passe-t-il si vous souhaitez évaluer YAML et identifier des violations comme la balise latest? Comment puis-je vérifier un fichier YAML par rapport aux meilleures pratiques ?

2. Score Kube

Score Kube analyse les manifestes YAML et les évalue par rapport aux tests intégrés. Ces tests sont sélectionnés en fonction des directives de sécurité et des meilleures pratiques, telles que :

  • Exécuter le conteneur pas en tant que root.
  • Disponibilité des contrôles de santé des pods.
  • Définition des demandes et des limites de ressources.

Sur la base des résultats des tests, trois résultats sont donnés : OK, ATTENTION и CRITIQUE.

Vous pouvez essayer Kube-score en ligne ou l'installer localement.

Au moment de la rédaction de l'article original, la dernière version de kube-score était la 1.7.0.

Essayons-le sur notre manifeste base-valid.yaml:

$ kube-score score base-valid.yaml

apps/v1/Deployment http-echo
[CRITICAL] Container Image Tag
  · http-echo -> Image with latest tag
      Using a fixed tag is recommended to avoid accidental upgrades
[CRITICAL] Pod NetworkPolicy
  · The pod does not have a matching network policy
      Create a NetworkPolicy that targets this pod
[CRITICAL] Pod Probes
  · Container is missing a readinessProbe
      A readinessProbe should be used to indicate when the service is ready to receive traffic.
      Without it, the Pod is risking to receive traffic before it has booted. It is also used during
      rollouts, and can prevent downtime if a new version of the application is failing.
      More information: https://github.com/zegl/kube-score/blob/master/README_PROBES.md
[CRITICAL] Container Security Context
  · http-echo -> Container has no configured security context
      Set securityContext to run the container in a more secure context.
[CRITICAL] Container Resources
  · http-echo -> CPU limit is not set
      Resource limits are recommended to avoid resource DDOS. Set resources.limits.cpu
  · http-echo -> Memory limit is not set
      Resource limits are recommended to avoid resource DDOS. Set resources.limits.memory
  · http-echo -> CPU request is not set
      Resource requests are recommended to make sure that the application can start and run without
      crashing. Set resources.requests.cpu
  · http-echo -> Memory request is not set
      Resource requests are recommended to make sure that the application can start and run without crashing.
      Set resources.requests.memory
[CRITICAL] Deployment has PodDisruptionBudget
  · No matching PodDisruptionBudget was found
      It is recommended to define a PodDisruptionBudget to avoid unexpected downtime during Kubernetes
      maintenance operations, such as when draining a node.
[WARNING] Deployment has host PodAntiAffinity
  · Deployment does not have a host podAntiAffinity set
      It is recommended to set a podAntiAffinity that stops multiple pods from a deployment from
      being scheduled on the same node. This increases availability in case the node becomes unavailable.

YAML réussit les tests Kubeval, tandis que Kube-score pointe les défauts suivants :

  • Les contrôles de préparation ne sont pas configurés.
  • Il n'y a aucune demande ni limite pour les ressources CPU et la mémoire.
  • Les budgets de perturbation des pods ne sont pas précisés.
  • Il n'y a pas de règles de séparation (anti-affinité) pour maximiser la disponibilité.
  • Le conteneur s'exécute en tant que root.

Ce sont tous des points valables sur les lacunes qui doivent être corrigées pour rendre le déploiement plus efficace et plus fiable.

Équipe kube-score affiche les informations sous une forme lisible par l'homme, y compris toutes les violations de type ATTENTION и CRITIQUE, ce qui aide beaucoup lors du développement.

Ceux qui souhaitent utiliser cet outil dans le pipeline CI peuvent activer une sortie plus compressée à l'aide de l'indicateur --output-format ci (dans ce cas, les tests avec le résultat sont également affichés OK):

$ kube-score score base-valid.yaml --output-format ci

[OK] http-echo apps/v1/Deployment
[OK] http-echo apps/v1/Deployment
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) CPU limit is not set
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Memory limit is not set
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) CPU request is not set
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Memory request is not set
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Image with latest tag
[OK] http-echo apps/v1/Deployment
[CRITICAL] http-echo apps/v1/Deployment: The pod does not have a matching network policy
[CRITICAL] http-echo apps/v1/Deployment: Container is missing a readinessProbe
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Container has no configured security context
[CRITICAL] http-echo apps/v1/Deployment: No matching PodDisruptionBudget was found
[WARNING] http-echo apps/v1/Deployment: Deployment does not have a host podAntiAffinity set
[OK] http-echo v1/Service
[OK] http-echo v1/Service
[OK] http-echo v1/Service
[OK] http-echo v1/Service

Semblable à Kubeval, Kube-score renvoie un code de sortie différent de zéro lorsqu'un test échoue CRITIQUE. Vous pouvez également activer un traitement similaire pour ATTENTION.

De plus, il est possible de vérifier la conformité des ressources avec les différentes versions de l'API (comme dans Kubeval). Cependant, ces informations sont codées en dur dans le kube-score lui-même : vous ne pouvez pas sélectionner une version différente de Kubernetes. Cette limitation peut constituer un gros problème si vous avez l'intention de mettre à niveau votre cluster ou si vous disposez de plusieurs clusters avec différentes versions de K8.

S'il vous plaît noter que il y a déjà un problème avec une proposition pour réaliser cette opportunité.

Plus d’informations sur le score kube peuvent être trouvées sur le site officiel.

Les tests Kube-score sont un excellent outil pour mettre en œuvre les meilleures pratiques, mais que se passe-t-il si vous devez apporter des modifications au test ou ajouter vos propres règles ? Hélas, cela ne peut pas être fait.

Kube-score n'est pas extensible : vous ne pouvez pas y ajouter de politiques ni les ajuster.

Si vous devez écrire des tests personnalisés pour vérifier la conformité aux politiques de l'entreprise, vous pouvez utiliser l'un des quatre outils suivants : config-lint, copper, conftest ou polaris.

3.Config-lint

Config-lint est un outil de validation des fichiers de configuration YAML, JSON, Terraform, CSV et des manifestes Kubernetes.

Vous pouvez l'installer en utilisant instructions sur le site du projet.

La version actuelle au moment de la rédaction de l'article original est la 1.5.0.

Config-lint n'a pas de tests intégrés pour valider les manifestes Kubernetes.

Pour effectuer des tests, vous devez créer des règles appropriées. Ils sont écrits dans des fichiers YAML appelés « ensembles de règles » (ensembles de règles), et ont la structure suivante :

version: 1
description: Rules for Kubernetes spec files
type: Kubernetes
files:
  - "*.yaml"
rules:
   # список правил

(rule.yaml)

Étudions-le de plus près :

  • Champ type spécifie le type de configuration que config-lint utilisera. Pour les manifestes K8, c'est toujours Kubernetes.
  • Dans l' files En plus des fichiers eux-mêmes, vous pouvez spécifier un répertoire.
  • Champ rules destiné à la mise en place de tests utilisateurs.

Supposons que vous souhaitiez vous assurer que les images du déploiement sont toujours téléchargées à partir d'un référentiel fiable tel que my-company.com/myapp:1.0. Une règle config-lint qui effectue une telle vérification ressemblerait à ceci :

- id: MY_DEPLOYMENT_IMAGE_TAG
  severity: FAILURE
  message: Deployment must use a valid image tag
  resource: Deployment
  assertions:
    - every:
        key: spec.template.spec.containers
        expressions:
          - key: image
            op: starts-with
            value: "my-company.com/"

(rule-trusted-repo.yaml)

Chaque règle doit avoir les attributs suivants :

  • id — identifiant unique de la règle ;
  • severity - peut être Analyse De Défaillance, ATTENTION и NON_CONFORME;
  • message — si une règle est violée, le contenu de cette ligne est affiché ;
  • resource — le type de ressource auquel cette règle s'applique ;
  • assertions — une liste de conditions qui seront évaluées par rapport à cette ressource.

Dans la règle ci-dessus assertion intitulé every vérifie que tous les conteneurs sont en déploiement (key: spec.templates.spec.containers) utilisez des images fiables (c'est-à-dire commençant par my-company.com/).

L'ensemble de règles complet ressemble à ceci :

version: 1
description: Rules for Kubernetes spec files
type: Kubernetes
files:
  - "*.yaml"
rules:

 - id: DEPLOYMENT_IMAGE_REPOSITORY # !!!
    severity: FAILURE
    message: Deployment must use a valid image repository
    resource: Deployment
    assertions:
      - every:
          key: spec.template.spec.containers
          expressions:
            - key: image
              op: starts-with
              value: "my-company.com/"

(ruleset.yaml)

Pour tester le test, sauvegardons-le sous check_image_repo.yaml. Vérifions le fichier base-valid.yaml:

$ config-lint -rules check_image_repo.yaml base-valid.yaml

[
  {
  "AssertionMessage": "Every expression fails: And expression fails: image does not start with my-company.com/",
  "Category": "",
  "CreatedAt": "2020-06-04T01:29:25Z",
  "Filename": "test-data/base-valid.yaml",
  "LineNumber": 0,
  "ResourceID": "http-echo",
  "ResourceType": "Deployment",
  "RuleID": "DEPLOYMENT_IMAGE_REPOSITORY",
  "RuleMessage": "Deployment must use a valid image repository",
  "Status": "FAILURE"
  }
]

Le contrôle a échoué. Examinons maintenant le manifeste suivant avec le référentiel d'images correct :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: http-echo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: http-echo
  template:
    metadata:
      labels:
        app: http-echo
    spec:
      containers:
      - name: http-echo
         image: my-company.com/http-echo:1.0 # !!!
         args: ["-text", "hello-world"]
         ports:
         - containerPort: 5678

(image-valid-mycompany.yaml)

Nous effectuons le même test avec le manifeste ci-dessus. Aucun problème trouvé:

$ config-lint -rules check_image_repo.yaml image-valid-mycompany.yaml
[]

Config-lint est un framework prometteur qui vous permet de créer vos propres tests pour valider les manifestes Kubernetes YAML à l'aide du YAML DSL.

Mais que se passe-t-il si vous avez besoin d’une logique et de tests plus complexes ? YAML n'est-il pas trop limité pour cela ? Et si vous pouviez créer des tests dans un langage de programmation complet ?

4. Cuivre

Cuivre V2 est un framework pour valider les manifestes à l'aide de tests personnalisés (similaire à config-lint).

Cependant, il diffère de ce dernier dans la mesure où il n’utilise pas YAML pour décrire les tests. Les tests peuvent être écrits en JavaScript à la place. Copper fournit une bibliothèque avec plusieurs outils de base, qui vous aident à lire des informations sur les objets Kubernetes et à signaler les erreurs.

Les étapes d'installation de Copper se trouvent dans documents officiels.

2.0.1 est la dernière version de cet utilitaire au moment de la rédaction de l'article original.

Comme config-lint, Copper n'a pas de tests intégrés. Écrivons-en un. Laissez-le vérifier que les déploiements utilisent des images de conteneurs exclusivement provenant de référentiels fiables tels que my-company.com.

Créer un fichier check_image_repo.js avec le contenu suivant :

$$.forEach(function($){
    if ($.kind === 'Deployment') {
        $.spec.template.spec.containers.forEach(function(container) {
            var image = new DockerImage(container.image);
            if (image.registry.lastIndexOf('my-company.com/') != 0) {
                errors.add_error('no_company_repo',"Image " + $.metadata.name + " is not from my-company.com repo", 1)
            }
        });
    }
});

Maintenant, testons notre manifeste base-valid.yaml, utilisez la commande copper validate:

$ copper validate --in=base-valid.yaml --validator=check_image_tag.js

Check no_company_repo failed with severity 1 due to Image http-echo is not from my-company.com repo
Validation failed

Il est clair qu'avec l'aide du cuivre, vous pouvez effectuer des tests plus complexes - par exemple, vérifier les noms de domaine dans les manifestes d'entrée ou rejeter les pods exécutés en mode privilégié.

Le cuivre intègre diverses fonctions utilitaires :

  • DockerImage lit le fichier d'entrée spécifié et crée un objet avec les attributs suivants :
    • name - le nom de l'image,
    • tag - balise d'image,
    • registry - registre d'images,
    • registry_url - protocole (https://) et registre d'images,
    • fqin — localisation complète de l'image.
  • Fonction findByName aide à trouver une ressource par un type donné (kind) et le nom (name) à partir du fichier d'entrée.
  • Fonction findByLabels aide à trouver une ressource par un type spécifié (kind) et les étiquettes (labels).

Vous pouvez afficher toutes les fonctions de service disponibles ici.

Par défaut, il charge l'intégralité du fichier YAML d'entrée dans une variable $$ et le rend disponible pour les scripts (une technique familière pour ceux qui ont une expérience jQuery).

Le principal avantage de Copper est évident : vous n'avez pas besoin de maîtriser un langage spécialisé et vous pouvez utiliser diverses fonctionnalités JavaScript pour créer vos propres tests, comme l'interpolation de chaînes, les fonctions, etc.

Il convient également de noter que la version actuelle de Copper fonctionne avec la version ES5 du moteur JavaScript, et non avec ES6.

Détails disponibles sur le site officiel du projet.

Cependant, si vous n'aimez pas vraiment JavaScript et préférez un langage spécialement conçu pour créer des requêtes et décrire des politiques, vous devez faire attention au concours.

5.Contest

Conftest est un framework pour tester les données de configuration. Convient également pour tester/vérifier les manifestes Kubernetes. Les tests sont décrits à l'aide d'un langage de requête spécialisé Rego.

Vous pouvez installer conftest en utilisant instructionsrépertoriés sur le site Internet du projet.

Au moment de la rédaction de l'article original, la dernière version disponible était la 0.18.2.

Semblable à config-lint et copper, conftest est livré sans aucun test intégré. Essayons-le et écrivons notre propre politique. Comme dans les exemples précédents, nous vérifierons si les images des conteneurs proviennent d’une source fiable.

Créer un répertoire conftest-checks, et dedans il y a un fichier nommé check_image_registry.rego avec le contenu suivant :

package main

deny[msg] {

  input.kind == "Deployment"
  image := input.spec.template.spec.containers[_].image
  not startswith(image, "my-company.com/")
  msg := sprintf("image '%v' doesn't come from my-company.com repository", [image])
}

Testons maintenant base-valid.yaml à travers conftest:

$ conftest test --policy ./conftest-checks base-valid.yaml

FAIL - base-valid.yaml - image 'hashicorp/http-echo' doesn't come from my-company.com repository
1 tests, 1 passed, 0 warnings, 1 failure

Comme on pouvait s’y attendre, le test a échoué car les images provenaient d’une source non fiable.

Dans le fichier Rego nous définissons le bloc deny. Sa véracité est considérée comme une violation. Si bloque deny plusieurs, conftest les vérifie indépendamment les uns des autres, et la vérité de l'un des blocs est traitée comme une violation.

En plus de la sortie par défaut, conftest prend en charge les formats JSON, TAP et tableau - une fonctionnalité extrêmement utile si vous devez intégrer des rapports dans un pipeline CI existant. Vous pouvez définir le format souhaité à l'aide du drapeau --output.

Pour faciliter le débogage des politiques, conftest a un indicateur --trace. Il génère une trace de la façon dont conftest analyse les fichiers de stratégie spécifiés.

Les politiques du concours peuvent être publiées et partagées dans les registres OCI (Open Container Initiative) en tant qu'artefacts.

Команды push и pull vous permettent de publier un artefact ou de récupérer un artefact existant à partir d'un registre distant. Essayons de publier la politique que nous avons créée dans le registre Docker local à l'aide de conftest push.

Démarrez votre registre Docker local :

$ docker run -it --rm -p 5000:5000 registry

Dans un autre terminal, accédez au répertoire que vous avez créé précédemment conftest-checks et exécutez la commande suivante :

$ conftest push 127.0.0.1:5000/amitsaha/opa-bundle-example:latest

Si la commande a réussi, vous verrez un message comme celui-ci :

2020/06/10 14:25:43 pushed bundle with digest: sha256:e9765f201364c1a8a182ca637bc88201db3417bacc091e7ef8211f6c2fd2609c

Créez maintenant un répertoire temporaire et exécutez la commande dedans conftest pull. Il téléchargera le package créé par la commande précédente :

$ cd $(mktemp -d)
$ conftest pull 127.0.0.1:5000/amitsaha/opa-bundle-example:latest

Un sous-répertoire apparaîtra dans le répertoire temporaire policycontenant notre fichier de politique :

$ tree
.
└── policy
  └── check_image_registry.rego

Les tests peuvent être exécutés directement depuis le référentiel :

$ conftest test --update 127.0.0.1:5000/amitsaha/opa-bundle-example:latest base-valid.yaml
..
FAIL - base-valid.yaml - image 'hashicorp/http-echo' doesn't come from my-company.com repository
2 tests, 1 passed, 0 warnings, 1 failure

Malheureusement, DockerHub n'est pas encore pris en charge. Alors considérez-vous chanceux si vous utilisez Registre de conteneurs Azure (ACR) ou votre propre registre.

Le format de l'artefact est le même que celui Ouvrir les packages de l'agent de stratégie (OPA), qui vous permet d'utiliser conftest pour exécuter des tests à partir de packages OPA existants.

Vous pouvez en savoir plus sur le partage de politiques et d’autres fonctionnalités de Confest sur le site officiel du projet.

6. Polaris

Le dernier outil qui sera abordé dans cet article est Polaris. (Son annonce de l'année dernière, nous déjà traduit - environ. traduction)

Polaris peut être installé dans un cluster ou utilisé en mode ligne de commande. Comme vous l'avez peut-être deviné, il vous permet d'analyser statiquement les manifestes Kubernetes.

Lors de l'exécution en mode ligne de commande, des tests intégrés sont disponibles couvrant des domaines tels que la sécurité et les meilleures pratiques (similaires à kube-score). De plus, vous pouvez créer vos propres tests (comme dans config-lint, copper et conftest).

En d’autres termes, Polaris combine les avantages des deux catégories d’outils : avec des tests intégrés et personnalisés.

Pour installer Polaris en mode ligne de commande, utilisez instructions sur le site Web du projet.

Au moment de la rédaction de l'article original, la version 1.0.3 est disponible.

Une fois l'installation terminée, vous pouvez exécuter Polaris sur le manifeste base-valid.yaml avec la commande suivante :

$ polaris audit --audit-path base-valid.yaml

Il affichera une chaîne au format JSON avec une description détaillée des tests effectués et de leurs résultats. La sortie aura la structure suivante :

{
  "PolarisOutputVersion": "1.0",
  "AuditTime": "0001-01-01T00:00:00Z",
  "SourceType": "Path",
  "SourceName": "test-data/base-valid.yaml",
  "DisplayName": "test-data/base-valid.yaml",
  "ClusterInfo": {
    "Version": "unknown",
    "Nodes": 0,
    "Pods": 2,
    "Namespaces": 0,
    "Controllers": 2
  },
  "Results": [
    /* длинный список */
  ]
}

Sortie complète disponible ici.

Comme Kube-score, Polaris identifie les problèmes dans les domaines où le manifeste ne répond pas aux meilleures pratiques :

  • Il n’y a aucun contrôle de santé pour les pods.
  • Les balises pour les images de conteneur ne sont pas spécifiées.
  • Le conteneur s'exécute en tant que root.
  • Les demandes et les limites de mémoire et de CPU ne sont pas spécifiées.

Chaque test, en fonction de ses résultats, se voit attribuer un degré de criticité : avertissement ou danger. Pour en savoir plus sur les tests intégrés disponibles, veuillez vous référer à documentation.

Si les détails ne sont pas nécessaires, vous pouvez spécifier le drapeau --format score. Dans ce cas, Polaris affichera un nombre allant de 1 à 100 - But (c'est-à-dire évaluation) :

$ polaris audit --audit-path test-data/base-valid.yaml --format score
68

Plus le score est proche de 100, plus le degré d’accord est élevé. Si vous vérifiez le code de sortie de la commande polaris audit, il s'avère qu'il est égal à 0.

Faire polaris audit Vous pouvez terminer le travail avec un code différent de zéro à l'aide de deux indicateurs :

  • Drapeau --set-exit-code-below-score prend comme argument une valeur seuil comprise entre 1 et 100. Dans ce cas, la commande se terminera avec le code de sortie 4 si le score est inférieur au seuil. Ceci est très utile lorsque vous avez une certaine valeur seuil (disons 75) et que vous devez recevoir une alerte si le score descend en dessous.
  • Drapeau --set-exit-code-on-danger entraînera l'échec de la commande avec le code 3 si l'un des tests de danger échoue.

Essayons maintenant de créer un test personnalisé qui vérifie si l'image provient d'un référentiel fiable. Les tests personnalisés sont spécifiés au format YAML et le test lui-même est décrit à l'aide du schéma JSON.

L'extrait de code YAML suivant décrit un nouveau test appelé checkImageRepo:

checkImageRepo:
  successMessage: Image registry is valid
  failureMessage: Image registry is not valid
  category: Images
  target: Container
  schema:
    '$schema': http://json-schema.org/draft-07/schema
    type: object
    properties:
      image:
        type: string
        pattern: ^my-company.com/.+$

Regardons-le de plus près :

  • successMessage — cette ligne sera imprimée si le test se termine avec succès ;
  • failureMessage — ce message sera affiché en cas d'échec ;
  • category — indique l'une des catégories : Images, Health Checks, Security, Networking и Resources;
  • target--- détermine quel type d'objet (spec) le test est appliqué. Valeurs possibles: Container, Pod ou Controller;
  • Le test lui-même est spécifié dans l'objet schema en utilisant le schéma JSON. Le mot clé de ce test est pattern utilisé pour comparer la source de l’image avec celle requise.

Pour exécuter le test ci-dessus, vous devez créer la configuration Polaris suivante :

checks:
  checkImageRepo: danger
customChecks:
  checkImageRepo:
    successMessage: Image registry is valid
    failureMessage: Image registry is not valid
    category: Images
    target: Container
    schema:
      '$schema': http://json-schema.org/draft-07/schema
      type: object
      properties:
        image:
          type: string
          pattern: ^my-company.com/.+$

(polaris-conf.yaml)

Analysons le fichier :

  • Dans l' checks des tests et leur niveau de criticité sont prescrits. Puisqu'il est souhaitable de recevoir un avertissement lorsqu'une image provient d'une source non fiable, nous définissons ici le niveau danger.
  • Le test lui-même checkImageRepo puis inscrit dans l'objet customChecks.

Enregistrez le fichier sous custom_check.yaml. Maintenant tu peux courir polaris audit avec un manifeste YAML qui nécessite une vérification.

Testons notre manifeste base-valid.yaml:

$ polaris audit --config custom_check.yaml --audit-path base-valid.yaml

Équipe polaris audit a exécuté uniquement le test utilisateur spécifié ci-dessus et il a échoué.

Si vous corrigez l'image sur my-company.com/http-echo:1.0, Polaris se fermera avec succès. Le manifeste avec les changements est déjà disponible référentielsafin que vous puissiez vérifier la commande précédente sur le manifeste image-valid-mycompany.yaml.

Maintenant, la question se pose : comment exécuter des tests intégrés avec des tests personnalisés ? Facilement! Il vous suffit d'ajouter les identifiants de test intégrés au fichier de configuration. De ce fait, cela prendra la forme suivante :

checks:
  cpuRequestsMissing: warning
  cpuLimitsMissing: warning
  # Other inbuilt checks..
  # ..
  # custom checks
  checkImageRepo: danger # !!!
customChecks:
  checkImageRepo:        # !!!
    successMessage: Image registry is valid
    failureMessage: Image registry is not valid
    category: Images
    target: Container
    schema:
      '$schema': http://json-schema.org/draft-07/schema
      type: object
      properties:
        image:
          type: string
          pattern: ^my-company.com/.+$

(config_with_custom_check.yaml)

Un exemple de fichier de configuration complet est disponible ici.

Vérifier le manifeste base-valid.yamlà l'aide de tests intégrés et personnalisés, vous pouvez utiliser la commande :

$ polaris audit --config config_with_custom_check.yaml --audit-path base-valid.yaml

Polaris complète les tests intégrés par des tests personnalisés, combinant ainsi le meilleur des deux mondes.

En revanche, l’impossibilité d’utiliser des langages plus puissants comme Rego ou JavaScript peut être un facteur limitant empêchant la création de tests plus sophistiqués.

Plus d’informations sur Polaris sont disponibles sur site du projet.

Résumé

Bien qu'il existe de nombreux outils disponibles pour inspecter et évaluer les fichiers YAML Kubernetes, il est important de bien comprendre comment les tests seront conçus et exécutés.

Par exemple, si vous prenez des manifestes Kubernetes passant par un pipeline, Kubeval pourrait être la première étape d'un tel pipeline. Il surveillerait si les définitions d'objets sont conformes au schéma de l'API Kubernetes.

Une fois cet examen terminé, on pourrait passer à des tests plus sophistiqués, tels que la conformité aux meilleures pratiques standard et aux politiques spécifiques. C'est là que Kube-score et Polaris seraient utiles.

Pour ceux qui ont des exigences complexes et ont besoin de personnaliser les tests en détail, copper, config-lint et conftest conviendraient..

Conftest et config-lint utilisent YAML pour définir des tests personnalisés, et Copper vous donne accès à un langage de programmation complet, ce qui en fait un choix assez attractif.

D'un autre côté, vaut-il la peine d'utiliser un de ces outils et donc de créer tous les tests manuellement, ou de préférer Polaris et d'y ajouter uniquement le nécessaire ? Il n'y a pas de réponse claire à cette question.

Le tableau ci-dessous fournit une brève description de chaque outil :

Outil
But
Limites
Tests utilisateurs

Kubeval
Valide les manifestes YAML par rapport à une version spécifique du schéma API
Je ne peux pas travailler avec CRD
Aucun

score Kube
Analyse les manifestes YAML par rapport aux meilleures pratiques
Impossible de sélectionner la version de votre API Kubernetes pour vérifier les ressources
Aucun

capuchons de cuivre
Un cadre général pour créer des tests JavaScript personnalisés pour les manifestes YAML
Aucun test intégré. Mauvaise documentation
Oui

config-lint
Un cadre général pour créer des tests dans un langage spécifique à un domaine intégré dans YAML. Prend en charge divers formats de configuration (par exemple Terraform)
Il n’existe pas de tests prêts à l’emploi. Les assertions et fonctions intégrées peuvent ne pas suffire
Oui

concours
Un framework pour créer vos propres tests à l'aide de Rego (un langage de requête spécialisé). Permet le partage de politiques via des bundles OCI
Aucun test intégré. Je dois apprendre Rego. Docker Hub n'est pas pris en charge lors de la publication de stratégies
Oui

Polaris
Examine les manifestes YAML par rapport aux meilleures pratiques standard. Vous permet de créer vos propres tests à l'aide du schéma JSON
Les capacités de test basées sur le schéma JSON peuvent ne pas être suffisantes
Oui

Étant donné que ces outils ne dépendent pas de l’accès au cluster Kubernetes, ils sont faciles à installer. Ils vous permettent de filtrer les fichiers sources et de fournir un retour rapide aux auteurs des pull request dans les projets.

PS du traducteur

A lire aussi sur notre blog :

Source: habr.com

Ajouter un commentaire