Validation du YAML Kubernetes pour se conformer aux meilleures pratiques et politiques

Note de traduction.: Avec l'augmentation du nombre de configurations YAML pour les environnements K8s, la nécessité de leur vérification automatisée devient de plus en plus pertinente. L'auteur de cette revue n'a pas seulement sélectionné les solutions existantes pour ce défi, mais a également examiné, à travers le déploiement, comment elles fonctionnent. Cela s'est avéré trÚs informatif pour ceux que ce sujet intéresse.

Validation du YAML Kubernetes pour se conformer aux meilleures pratiques et politiques

TL;DR: Cet article compare six outils d'analyse statique pour vérifier et évaluer les fichiers YAML de Kubernetes en fonction des meilleures pratiques et exigences.

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

Que faire si nous devons nous assurer que toutes les images déployées dans le cluster proviennent d'un registre de confiance ?

Comment empĂȘcher l'envoi dans le cluster des dĂ©ploiements pour lesquels aucun PodDisruptionBudget n'est dĂ©fini ?

L'intégration des tests statiques permet de détecter les erreurs et les violations de politiques dÚs la phase de développement. Cela augmente ainsi les garanties de validité et de sécurité des définitions des ressources, et accroßt la probabilité que les charges de production suivent les meilleures pratiques.

L'Ă©cosystĂšme de vĂ©rification statique des fichiers YAML de Kubernetes peut ĂȘtre divisĂ© en plusieurs catĂ©gories :

  • Validateurs API. Les outils de cette catĂ©gorie vĂ©rifient si le manifeste YAML rĂ©pond aux exigences du serveur API Kubernetes.
  • Testeurs prĂȘts Ă  l'emploi. Les outils de cette catĂ©gorie viennent avec des tests prĂȘts Ă  l'emploi sur la sĂ©curitĂ©, la conformitĂ© aux meilleures pratiques, etc.
  • Validateurs personnalisĂ©s. Les reprĂ©sentants de cette catĂ©gorie permettent de crĂ©er des tests personnalisĂ©s dans divers langages, tels que Rego et Javascript.

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

  1. kubeval;
  2. kube-score;
  3. config-lint;
  4. copper;
  5. conftest;
  6. Polaris.

Alors, commençons !

Vérification des déploiements

Avant d'entamer la comparaison des outils, créons une base sur laquelle nous allons les tester.

Le manifeste ci-dessous contient plusieurs erreurs et non-conformités aux meilleures pratiques : combien d'entre elles pourrez-vous 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 allons utiliser 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ĂŽt Git.

Le manifeste dĂ©crit une application web dont la principale tĂąche est de rĂ©pondre avec le message «Hello World» sur le port 5678. Il peut ĂȘtre dĂ©ployĂ© avec la commande suivante :

kubectl apply -f hello-world.yaml

Et voici comment vérifier si ça fonctionne :

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

Maintenant, allez sur http://localhost:8080 et confirmez que l'application fonctionne. Mais respecte-t-elle les meilleures pratiques ? Vérifions.

1. Kubeval

Au cƓur de kubeval se trouve l'idĂ©e que toute interaction avec Kubernetes passe par son API REST. En d'autres termes, il est possible d'utiliser le schĂ©ma API pour vĂ©rifier si le YAML donnĂ© y correspond. Regardons un exemple.

Les instructions d'installation de kubeval sont disponibles sur le site du projet.

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

AprĂšs l'installation, fournissons-lui le manifeste ci-dessus :

$ kubeval base-valid.yaml
PASS - base-valid.yaml contient un Deployment valide (http-echo)
PASS - base-valid.yaml contient un Service valide (http-echo)

En cas de succÚs, kubeval terminera avec un code de sortie 0. On peut vérifier cela de la maniÚre suivante :

$ 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 identifier le problĂšme Ă  l'Ɠil nu ? ExĂ©cutons :

$ kubeval kubeval-invalid.yaml
WARN - kubeval-invalid.yaml contient un Deployment invalide (http-echo) - selector: le sélecteur est requis
PASS - kubeval-invalid.yaml contient un Service valide (http-echo)

# vérifions le code de retour
$ echo $?
1

La ressource ne passe pas la validation.

Les Deployments utilisant une version de l'API apps/v1, doivent inclure un sélecteur correspondant à l'étiquette du pod. Le manifeste ci-dessus n'inclut pas de sélecteur, c'est pourquoi kubeval a signalé une erreur et s'est terminé avec un code non nul.

Je me demande ce qui se passerait si nous exécutons kubectl apply -f avec ce manifeste ?

Eh bien, essayons :

$ kubectl apply -f kubeval-invalid.yaml
error: error validating "kubeval-invalid.yaml": erreur de validation des données: ValidationError(Deployment.spec):
champ obligatoire "selector" manquant dans io.k8s.api.apps.v1.DeploymentSpec ; si vous choisissez d'ignorer ces erreurs,
désactivez la validation avec --validate=false

C'est exactement l'erreur dont kubeval avertissait. Vous pouvez la corriger 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 des outils comme kubeval est que de telles erreurs peuvent ĂȘtre dĂ©tectĂ©es Ă  un stade prĂ©coce du cycle de dĂ©ploiement.

De plus, aucune connexion au cluster n'est requise pour ces vĂ©rifications : elles peuvent ĂȘtre effectuĂ©es hors ligne.

Par dĂ©faut, kubeval vĂ©rifie que les ressources correspondent au dernier schĂ©ma de l'API Kubernetes. Cependant, dans la plupart des cas, vous souhaitez vĂ©rifier la conformitĂ© Ă  une version spĂ©cifique de Kubernetes. Cela peut ĂȘtre fait Ă  l'aide de l'option --kubernetes-version:

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

Notez que la version doit ĂȘtre indiquĂ©e au format Major.Minor.Patch.

Pour voir la liste des versions prises en charge pour la validation, consultez la 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 de l'option --schema-location.

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

De plus, Kubeval s'intÚgre facilement aux pipelines 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. Test Anything Protocol (TAP).

Et chacun des formats peut ĂȘtre utilisĂ© pour un parsing ultĂ©rieur de la sortie, afin de gĂ©nĂ©rer un rĂ©sumĂ© des rĂ©sultats au format souhaitĂ©.

Un des inconvĂ©nients de kubeval est qu'actuellement, il ne peut pas vĂ©rifier la conformitĂ© des Custom Resource Definitions (CRDs). Cependant, kubeval peut ĂȘtre configurĂ© pour les ignorer.

Kubeval est un excellent outil pour vérifier et évaluer les ressources ; cependant, il convient de souligner qu'un test réussi ne garantit pas que la ressource respecte les meilleures pratiques.

Par exemple, l'utilisation de l'étiquette latest Le conteneur ne respecte pas les meilleures pratiques. Cependant, kubeval ne considÚre pas cela comme une erreur et ne le signale pas. Cela signifie qu'un tel YAML se terminera sans avertissements.

Mais que faire si vous devez Ă©valuer le YAML et identifier des violations comme le tag latest? КаĐș ĐżŃ€ĐŸĐČĐ”Ń€ĐžŃ‚ŃŒ YAML-фаĐčĐ» ĐœĐ° ŃĐŸĐŸŃ‚ĐČДтстĐČОД Đ»ŃƒŃ‡ŃˆĐžĐŒ праĐșтоĐșĐ°ĐŒ?

2. Kube-score

Kube-score analyse les manifestes YAML et les évalue selon des tests intégrés. Ces tests sont choisis sur la base de recommandations de sécurité et des meilleures pratiques, par exemple :

  • ExĂ©cuter le conteneur sans root.
  • PrĂ©sence de contrĂŽles de santĂ© des pods.
  • DĂ©finir des demandes et des limites de ressources.

À l'issue du test, trois rĂ©sultats sont gĂ©nĂ©rĂ©s : OK, AVERTISSEMENT et CRITIQUE.

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

Au moment de la rédaction de l'article original, la version la plus récente de kube-score était 1.7.0.

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

$ kube-score score base-valid.yaml

apps/v1/Deployment http-echo
[CRITIQUE] Tag de l'image du conteneur
  · http-echo -> Image avec le tag latest
      Il est recommandé d'utiliser un tag fixe pour éviter les mises à jour accidentelles
[CRITIQUE] Pod NetworkPolicy
  · Le pod n'a pas de politique réseau correspondante
      Créez une NetworkPolicy qui cible ce pod
[CRITIQUE] Pod Probes
  · Le conteneur n'a pas de readinessProbe
      Une readinessProbe doit ĂȘtre utilisĂ©e pour indiquer quand le service est prĂȘt Ă  recevoir du trafic.
      Sans cela, le Pod risque de recevoir du trafic avant d'avoir démarré. Cela est également utilisé lors des
      dĂ©ploiements et peut Ă©viter des temps d'arrĂȘt si une nouvelle version de l'application Ă©choue.
      Plus d'informations : https://github.com/zegl/kube-score/blob/master/README_PROBES.md
[CRITIQUE] Contexte de sécurité du conteneur
  · http-echo -> Le conteneur n'a pas de contexte de sécurité configuré
      Définissez securityContext pour exécuter le conteneur dans un contexte plus sécurisé.
[CRITIQUE] Ressources du conteneur
  · http-echo -> La limite de CPU n'est pas définie
      Des limites de ressources sont recommandées pour éviter un DDOS de ressources. Définissez resources.limits.cpu
  · http-echo -> La limite de mémoire n'est pas définie
      Des limites de ressources sont recommandées pour éviter un DDOS de ressources. Définissez resources.limits.memory
  · http-echo -> La demande de CPU n'est pas définie
      Les demandes de ressources sont recommandées pour s'assurer que l'application peut démarrer et fonctionner sans
      planter. Définissez resources.requests.cpu
  · http-echo -> La demande de mémoire n'est pas définie
      Les demandes de ressources sont recommandées pour s'assurer que l'application peut démarrer et fonctionner sans
      planter. Définissez resources.requests.memory
[CRITIQUE] Le déploiement a un PodDisruptionBudget
  · Aucun PodDisruptionBudget correspondant n'a été trouvé
      Il est recommandĂ© de dĂ©finir un PodDisruptionBudget pour Ă©viter des temps d'arrĂȘt inattendus lors des opĂ©rations de
      maintenance de Kubernetes, telles que le drainage d'un nƓud.
[AVERTISSEMENT] Le déploiement a un PodAntiAffinity hÎte
  · Le déploiement n'a pas de podAntiAffinity hÎte défini
      Il est recommandĂ© de dĂ©finir un podAntiAffinity qui empĂȘche plusieurs pods d'un dĂ©ploiement d'ĂȘtre
      programmĂ©s sur le mĂȘme nƓud. Cela augmente la disponibilitĂ© en cas de dĂ©faillance du nƓud.

Le YAML passe les vérifications de kubeval, tandis que kube-score pointe les lacunes suivantes :

  • Les vĂ©rifications de disponibilitĂ© ne sont pas configurĂ©es.
  • Les demandes et limites pour les ressources CPU et mĂ©moire sont absentes.
  • Les budgets de perturbation des Pod ne sont pas dĂ©finis.
  • Les rĂšgles de coexistence sĂ©parĂ©e sont absentes. (anti-affinity) pour maximiser la disponibilitĂ©.
  • Le conteneur s'exĂ©cute avec les privilĂšges root.

Tout cela constitue des remarques valables sur les lacunes à corriger pour rendre le déploiement plus efficace et fiable.

Commande kube-score affiche les informations dans un format lisible en incluant toutes les violations de type AVERTISSEMENT et CRITIQUE, ce qui est trÚs utile durant le développement.

Ceux qui souhaitent utiliser cet outil dans le cadre d'un pipeline CI peuvent activer une sortie plus concise en utilisant le drapeau --output-format ci (dans ce cas, les tests avec des résultats 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) La limite CPU n'est pas définie
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) La limite mémoire n'est pas définie
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) La demande CPU n'est pas définie
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) La demande mémoire n'est pas définie
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Image avec le tag latest
[OK] http-echo apps/v1/Deployment
[CRITICAL] http-echo apps/v1/Deployment: Le pod n'a pas de politique réseau correspondante
[CRITICAL] http-echo apps/v1/Deployment: Le conteneur n'a pas de readinessProbe configurée
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Le conteneur n'a pas de contexte de sécurité configuré
[CRITICAL] http-echo apps/v1/Deployment: Aucun PodDisruptionBudget correspondant trouvé
[WARNING] http-echo apps/v1/Deployment: Le déploiement n'a pas de podAntiAffinity configuré
[OK] http-echo v1/Service
[OK] http-echo v1/Service
[OK] http-echo v1/Service
[OK] http-echo v1/Service

Tout comme kubeval, kube-score retourne un code de sortie non nul en cas d'échec d'un test. CRITIQUE. Il est également possible d'activer ce type de traitement pour AVERTISSEMENT.

De plus, il est possible de vérifier les ressources pour qu'elles soient conformes à différentes versions de l'API (comme avec kubeval). Cependant, cette information est 'hardcodée' dans kube-score : il n'est pas possible de choisir une autre version de Kubernetes. Cette limitation peut devenir un gros problÚme si vous prévoyez de mettre à jour le cluster ou si vous avez plusieurs clusters avec différentes versions de K8s.

Veuillez noter que il existe dĂ©jĂ  un problĂšme avec la suggestion de mettre en Ɠuvre cette possibilitĂ©.

Pour en savoir plus sur kube-score, consultez site officiel.

Les tests kube-score sont un excellent outil pour mettre en Ɠuvre des meilleures pratiques, mais que faire si des modifications doivent ĂȘtre apportĂ©es au test ou si vous souhaitez ajouter vos propres rĂšgles ? Malheureusement, cela n'est pas possible.

Kube-score n'est pas extensible : il n'est pas possible d'ajouter ou d'ajuster des politiques.

Si vous devez écrire des tests personnalisés pour vérifier la conformité aux politiques adoptées par 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 au format YAML, JSON, Terraform, CSV et des manifestes Kubernetes.

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

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

Config-lint ne contient pas de tests intégrés pour vérifier les manifestes Kubernetes.

Pour effectuer des tests, il est nécessaire de créer des rÚgles correspondantes. Celles-ci sont enregistrées dans des fichiers YAML, appelés 'ensembles de rÚgles' (rulesets), et ont la structure suivante :

version: 1
description: RÚgles pour les fichiers de spécification Kubernetes
type: Kubernetes
files:
  - "*.yaml"
rules:
   # liste des rĂšgles

(rule.yaml)

Examinons-le de plus prĂšs :

  • Champ type indique quel type de configuration utilisera config-lint. Pour les manifestes K8s, cela ont toujours Kubernetes.
  • Dans le champ files en plus des fichiers eux-mĂȘmes, vous pouvez spĂ©cifier un rĂ©pertoire.
  • Champ rules est destinĂ© Ă  dĂ©finir des tests personnalisĂ©s.

Supposons que vous souhaitiez vous assurer que les images dans le Deployment sont toujours téléchargées à partir d'un dépÎt de confiance tel que my-company.com/myapp:1.0. La rÚgle pour config-lint effectuant cette vérification ressemblera à ceci :

- id: MY_DEPLOYMENT_IMAGE_TAG
  severity: FAILURE
  message: Le déploiement doit utiliser une balise d'image valide
  resource: Deployment
  assertions:
    - every:
        key: spec.template.spec.containers
        expressions:
          - key: image
            op: starts-with
            value: "my-company.com/"

(rule-trusted-repo.yaml)

Pour chaque rĂšgle, les attributs suivants doivent ĂȘtre spĂ©cifiĂ©s :

  • id — un identifiant unique pour la rĂšgle ;
  • severity — peut ĂȘtre FAILURE, AVERTISSEMENT et NON_COMPLIANT;
  • message — lorsque la rĂšgle est violĂ©e, le contenu de cette ligne sera affichĂ© ;
  • resource — le type de ressource auquel cette rĂšgle s'applique ;
  • assertions — liste des conditions qui seront Ă©valuĂ©es pour cette ressource.

Dans la rÚgle ci-dessus, l'assertion appelé every vérifie que tous les conteneurs dans le Deployment (key: spec.templates.spec.containers) utilisent des images de confiance (c'est-à-dire commençant par my-company.com/).

L'ensemble de rĂšgles complet ressemble Ă  ceci :

version: 1
description: RÚgles pour les fichiers de spécification Kubernetes
type: Kubernetes
files:
  - "*.yaml"
rules:

 - id: DEPLOYMENT_IMAGE_REPOSITORY # !!!
    severity: FAILURE
    message: Le déploiement doit utiliser un dépÎt d'image valide
    resource: Deployment
    assertions:
      - every:
          key: spec.template.spec.containers
          expressions:
            - key: image
              op: starts-with
              value: "my-company.com/"

(ruleset.yaml)

Pour tester la rÚgle, enregistrons-la sous check_image_repo.yaml. Exécutons la vérification sur le fichier. base-valid.yaml:

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

[
  {
  "AssertionMessage": "Chaque expression échoue : L'expression 'Et' échoue : l'image ne commence pas par 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": "Le déploiement doit utiliser un référentiel d'images valide",
  "Status": "ÉCHEC"
  }
]

La vérification a échoué. Vérifions maintenant le prochain manifeste avec un référentiel d'images valide :

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 exĂ©cutons le mĂȘme test avec le manifeste ci-dessus. Aucun problĂšme dĂ©tectĂ© :

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

Config-lint est un cadre prometteur permettant de créer des tests personnalisés pour vérifier les manifestes YAML Kubernetes à l'aide de YAML DSL.

Mais que faire si une logique et des tests plus complexes sont nécessaires ? Les possibilités de YAML ne sont-elles pas trop limitées pour cela ? Que diriez-vous de pouvoir créer des tests dans un véritable langage de programmation ?

4. Copper

Copper V2 est un cadre de validation des manifestes via des tests personnalisés (similaire à config-lint).

Cependant, il se distingue de ce dernier en ce qu'il n'utilise pas YAML pour dĂ©crire les tests. Au lieu de cela, les tests peuvent ĂȘtre créés en JavaScript. Copper fournit une bibliothĂšque avec plusieurs outils de base, aidant Ă  lire les informations sur les objets Kubernetes et Ă  signaler les erreurs.

La sĂ©quence des Ă©tapes pour installer Copper peut ĂȘtre trouvĂ©e dans la documentation officielle.

2.0.1 — la version la plus rĂ©cente de cet outil au moment de la rĂ©daction de l'article original.

Tout comme config-lint, Copper n'a pas de tests intĂ©grĂ©s. Écrivons-en un. Qu'il vĂ©rifie que les dĂ©ploiements utilisent exclusivement des images de conteneurs provenant de rĂ©fĂ©rentiels de confiance comme my-company.com.

Créez 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 + " ne provient pas du référentiel my-company.com", 1)
            }
        });
    }
});

Maintenant, pour vérifier notre manifeste base-valid.yaml, utilisez la commande copper validate:

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

Le contrÎle no_company_repo a échoué avec une gravité de 1 parce que l'image http-echo ne provient pas du référentiel my-company.com
La validation a échoué

Il est Ă©vident qu'avec Copper, il est possible de rĂ©aliser des tests plus complexes — par exemple, vĂ©rifier les noms de domaine dans les manifests Ingress ou rejeter des pods fonctionnant en mode privilĂ©giĂ©.

Copper intĂšgre diverses fonctions utilitaires :

  • DockerImage lit le fichier d'entrĂ©e spĂ©cifiĂ© et crĂ©e un objet avec les attributs suivants :
    • nom — le nom de l'image,
    • tag — le tag de l'image,
    • registry — le registre des images,
    • registry_url — le protocole (https://) et le registre des images,
    • fqin — l'emplacement complet de l'image.
  • Fonction findByName aide Ă  trouver une ressource par un type donnĂ© (kind) et un nom (nom) dans le fichier d'entrĂ©e.
  • Fonction findByLabels aide Ă  trouver une ressource par un type spĂ©cifiĂ© (kind) et des Ă©tiquettes (labels).

Vous pouvez explorer toutes les fonctions utilitaires disponibles ici.

Par défaut, il charge tout le fichier YAML d'entrée dans une variable $$ et le rend accessible aux scripts (méthode familiÚre pour ceux qui ont de l'expérience avec jQuery).

Le principal avantage de Copper est évident : vous n'avez pas besoin d'apprendre un langage spécialisé et vous pouvez utiliser diverses fonctionnalités de JavaScript pour créer vos propres tests, telles que l'interpolation de chaßnes, des 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.

Les détails sont disponibles sur du site officiel du projet.

Cependant, si vous n'aimez pas beaucoup JavaScript et prĂ©fĂ©rez un langage spĂ©cifiquement conçu pour crĂ©er des requĂȘtes et dĂ©crire des politiques, vous devriez jeter un Ɠil Ă  conftest.

5. Conftest

Conftest est un framework pour la vĂ©rification des donnĂ©es de configuration. Il convient Ă©galement pour le test/la vĂ©rification des manifests Kubernetes. Les tests sont dĂ©crits Ă  l'aide d'un langage de requĂȘte spĂ©cialisĂ© Rego.

Vous pouvez installer conftest en suivant les instructions les instructionsdisponibles sur le site du projet.

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

À l'instar de config-lint et de copper, conftest ne comprend pas de tests intĂ©grĂ©s. Essayons-le et Ă©crivons notre propre politique. Comme dans les exemples prĂ©cĂ©dents, nous allons vĂ©rifier si les images des conteneurs proviennent d'une source fiable.

Créez un répertoire conftest-checks, puis dans celui-ci, 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("l'image '%v' ne provient pas du dépÎt my-company.com", [image])
}

Maintenant, testons base-valid.yaml via conftest:

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

ÉCHOUÉ - base-valid.yaml - l'image 'hashicorp/http-echo' ne provient pas du dĂ©pĂŽt my-company.com
1 tests, 1 réussi, 0 avertissements, 1 échec

Le test a échoué comme prévu, car les images proviennent d'une source non fiable.

Dans le fichier Rego, nous définissons le bloc deny. Sa validité est considérée comme une violation. Si plusieurs blocs deny sont présents, conftest les vérifie indépendamment les uns des autres, et la validité de n'importe quel bloc est interprétée comme une violation.

En plus de la sortie par dĂ©faut, conftest prend en charge JSON, TAP et le format tabulaire — une fonctionnalitĂ© extrĂȘmement utile si vous devez intĂ©grer des rapports dans un pipeline CI existant. Le format requis peut ĂȘtre dĂ©fini Ă  l'aide du drapeau --output.

Pour faciliter le débogage des politiques, conftest dispose d'un drapeau --trace. Il affiche une trace de la façon dont conftest analyse les fichiers de politiques spécifiés.

Les politiques de conftest peuvent ĂȘtre publiĂ©es et partagĂ©es dans des registres OCI (Open Container Initiative) sous forme d'artefacts.

Commandes push et pull permettent de publier un artefact ou d'extraire un artefact existant d'un registre distant. Essayons de publier la politique que nous avons créée dans un registre Docker local à l'aide de conftest push.

Démarrez un 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 réussit, vous verrez un message de type suivant :

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

Maintenant, créez un répertoire temporaire et exécutez-y la commande conftest pull. Elle téléchargera le paquet créé par la commande précédente :

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

Dans le répertoire temporaire, un sous-répertoire apparaßtra policy, contenant notre fichier de politique :

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

Les tests peuvent ĂȘtre effectuĂ©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. Donc, considérez-vous chanceux si vous utilisez Azure Container Registry (ACR) ou votre propre registre.

Le format des artefacts est identique à celui des paquets Open Policy Agent (OPA), ce qui permet d'utiliser conftest pour exécuter des tests à partir de paquets OPA existants.

Pour en savoir plus sur le partage des politiques et d'autres fonctionnalités de conftest, consultez du site officiel du projet.

6. Polaris

Le dernier outil dont nous allons parler dans cet article est Polaris. (Nous avons dĂ©jĂ  traduit son annonce de l'annĂ©e derniĂšre ) — Note de traduction.)

Polaris peut ĂȘtre installĂ© dans un cluster ou utilisĂ© en mode ligne de commande. Comme vous l'avez probablement devinĂ©, il permet une analyse statique des manifestes Kubernetes.

En mode ligne de commande, des tests intégrés sont disponibles, couvrant des domaines tels que la sécurité et les meilleures pratiques (similaire à 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 les instructions sur le site du projet..

Au moment de la rédaction de cet article, la version 1.0.3 est disponible.

AprÚs l'installation, vous pouvez exécuter polaris sur le manifeste base-valid.yaml avec la commande suivante :

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

Cela affichera une ligne au format JSON avec des détails sur les tests effectués et 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": [
    /* longue liste */
  ]
}

La sortie complĂšte est disponible. ici.

Comme kube-score, Polaris identifie les problĂšmes dans les domaines oĂč le manifeste ne respecte pas les meilleures pratiques :

  • Les vĂ©rifications de santĂ© des pods sont manquantes.
  • Les balises pour les images de conteneurs ne sont pas spĂ©cifiĂ©es.
  • Le conteneur s'exĂ©cute avec les privilĂšges root.
  • Les demandes et limites pour la mĂ©moire et le CPU ne sont pas spĂ©cifiĂ©es.

Chaque test se voit attribuer un niveau de criticité en fonction de ses résultats : warning ou danger. Pour en savoir plus sur les tests intégrés disponibles, veuillez consulter 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 dans la plage de 1 Ă  100 — score (c'est-Ă -dire une Ă©valuation) :

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

Plus l'évaluation est proche de 100, plus le degré de conformité est élevé. Si vous vérifiez le code de sortie de la commande polaris audit, il s'avérera égal à 0.

Forcer polaris audit Ă  quitter avec un code non nul peut ĂȘtre rĂ©alisĂ© avec deux drapeaux :

  • Drapeau --set-exit-code-below-score prend comme argument un seuil entre 1 et 100. Dans ce cas, la commande terminera avec un code de sortie 4 si l'Ă©valuation est infĂ©rieure au seuil. C'est trĂšs pratique lorsque vous avez un certain seuil (disons 75), et que vous devez recevoir une alerte si l'Ă©valuation tombe en dessous.
  • Drapeau --set-exit-code-on-danger Cela entraĂźnera l'Ă©chec de l'Ă©quipe 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 de confiance. Les tests personnalisĂ©s sont dĂ©finis au format YAML, et le test lui-mĂȘme est dĂ©crit Ă  l'aide de JSON Schema.

Le fragment YAML suivant décrit un nouveau test appelé checkImageRepo:

checkImageRepo:
  successMessage: Le registre d'images est valide
  failureMessage: Le registre d'images n'est pas valide
  category: Images
  target: Conteneur
  schema:
    '$schema': http://json-schema.org/draft-07/schema
    type: object
    properties:
      image:
        type: string
        pattern: ^my-company.com/.+$

Examinons-le de plus prĂšs :

  • successMessage — cette ligne sera affichĂ©e si le test rĂ©ussit ;
  • failureMessage — ce message sera affichĂ© en cas d'Ă©chec ;
  • category — indique l'une des catĂ©gories : Images, ContrĂŽles de santĂ©, SĂ©curitĂ©, RĂ©seau et Ressources;
  • cible— dĂ©termine Ă  quel type d'objet (spec) le test s'applique. Valeurs possibles : Conteneur, Pod ou ContrĂŽleur;
  • Le test lui-mĂȘme est dĂ©fini dans un objet schĂ©ma Ă  l'aide de JSON schema. Dans ce test, le mot-clĂ© pattern est utilisĂ© pour comparer la source de l'image avec celle requise.

Pour exécuter le test ci-dessus, il est nécessaire de créer la configuration Polaris suivante :

checks:
  checkImageRepo: danger
customChecks:
  checkImageRepo:
    successMessage: Le registre d'images est valide
    failureMessage: Le registre d'images n'est pas valide
    category: Images
    target: Conteneur
    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 le champ checks dĂ©crit les tests et leur niveau de criticitĂ©. Étant donnĂ© qu'il est souhaitable de recevoir une alerte lorsque l'image provient d'une source non fiable, nous dĂ©finissons ici le niveau danger.
  • Le test lui-mĂȘme checkImageRepo est ensuite dĂ©fini dans l'objet customChecks.

Enregistrez le fichier sous custom_check.yaml. Vous pouvez maintenant exécuter polaris audit avec le manifeste YAML nécessitant une vérification.

Testons notre manifeste base-valid.yaml:

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

Commande polaris audit a effectué uniquement le test personnalisé décrit ci-dessus, et il a échoué.

Si vous modifiez l'image en my-company.com/http-echo:1.0, Polaris réussira. Le manifeste avec les changements est déjà présent dans dépÎts, donc vous pouvez vérifier la commande précédente sur le manifeste. image-valid-mycompany.yaml.

Maintenant, la question se pose : comment exécuter les tests intégrés avec les tests personnalisés ? C'est simple ! Il suffit d'ajouter les identifiants des tests intégrés dans le fichier de configuration. Il finira par ressembler à ceci :

vérifications:
  cpuRequestsMissing: avertissement
  cpuLimitsMissing: avertissement
  # Autres vérifications intégrées..
  # ..
  # vérifications personnalisées
  checkImageRepo: danger # !!!
vérificationsPersonnalisées:
  checkImageRepo:        # !!!
    successMessage: Le registre d'images est valide
    failureMessage: Le registre d'images n'est pas valide
    category: Images
    target: Conteneur
    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 complet de fichier de configuration est disponible ici.

Vérifier le manifeste base-valid.yaml, en utilisant des tests intégrés et personnalisés, peut se faire avec 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.

D'un autre cĂŽtĂ©, l'incapacitĂ© Ă  utiliser des langages plus puissants comme Rego ou JavaScript peut ĂȘtre un facteur limitant qui empĂȘche la crĂ©ation de tests plus sophistiquĂ©s.

Des informations supplémentaires sur Polaris sont disponibles sur site du projet.

Résumé

Bien qu'il existe de nombreux outils pour vérifier et évaluer les fichiers YAML de Kubernetes, il est important d'avoir une idée claire de la façon dont les tests seront conçus et exécutés.

Par exemple, si l'on prend des manifestes Kubernetes passant par le pipeline, kubeval pourrait ĂȘtre le premier pas dans un tel pipeline. Il vĂ©rifierait si les dĂ©finitions d'objets correspondent au schĂ©ma API de Kubernetes.

AprÚs avoir terminé une telle vérification, il serait possible de passer à des tests plus sophistiqués, tels que la conformité aux meilleures pratiques standards et aux politiques spécifiques. Et c'est ici 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 seraient appropriés..

Conftest et config-lint utilisent YAML pour spécifier des tests personnalisés, tandis que copper donne accÚs à un langage de programmation complet, ce qui en fait un choix assez attrayant.

D'un autre cÎté, vaut-il mieux utiliser l'un de ces outils et donc créer tous les tests manuellement, ou préférer Polaris et simplement compléter ce dont on a besoin ? Il n'y a pas de réponse unique à cette question.

Le tableau ci-dessous contient une brĂšve description de chaque outil :

Outil
L'objectif
Inconvénients
Tests personnalisés

kubeval
Vérifie les manifestes YAML pour la conformité à une version spécifique du schéma API
Ne peut pas travailler avec des CRD
Non

kube-score
Analyse les manifestes YAML pour la conformité aux meilleures pratiques
On ne peut pas choisir sa version de l'API Kubernetes pour vérifier les ressources
Non

copper
Cadre général pour la création de tests JavaScript personnalisés pour des manisfestes YAML
Pas de tests intégrés. Documentation limitée
Oui

config-lint
Cadre général pour la création de tests dans un langage orienté objet intégré dans YAML. Prend en charge divers formats de configuration (par exemple, Terraform)
Pas de tests prĂ©conçus. Les assertions et fonctions intĂ©grĂ©es peuvent ĂȘtre insuffisantes
Oui

conftest
Cadre pour crĂ©er des tests personnalisĂ©s en Rego (langage de requĂȘte spĂ©cialisĂ©). Permet de partager des politiques via des bundles OCI
Pas de tests intégrés. Nécessite d'apprendre Rego. Docker Hub n'est pas pris en charge lors de la publication des politiques
Oui

Polaris
Analyse les manifestes YAML pour se conformer aux meilleures pratiques standards. Permet de créer des tests personnalisés à l'aide de JSON Schema
Les capacitĂ©s de test basĂ©es sur JSON Schema peuvent ĂȘtre insuffisantes
Oui

Étant donnĂ© que ces outils ne dĂ©pendent pas de l'accĂšs Ă  un cluster Kubernetes, ils sont faciles Ă  installer. Ils permettent de filtrer les fichiers sources et offrent des retours rapides aux auteurs de pull requests dans les projets.

P.S. de l'auteur

Lisez aussi dans notre blog :

Source : habr.com

Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS đŸ”„ Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster