Aller au contenu
Conteneurs & Orchestration medium

kube-score : analyser la qualité de ses manifests Kubernetes

11 min de lecture

logo kube-score

kube-score analyse statiquement vos manifests Kubernetes et liste les défauts de fiabilité et de sécurité, avant tout déploiement. Un kubectl apply accepte un manifest sans ressources, sans probes ni securityContext ; kube-score, lui, les signale. Ce guide montre comment l'installer, interpréter ses recommandations sur de vraies sorties, l'intégrer en CI/CD, et le situer face à Polaris, KubeLinter et Trivy. Pour utilisateurs Kubernetes intermédiaires. Outil open source (MIT, Go) ; sorties d'un lab réel avec kube-score 1.20.0.

  • Scanner un manifest avec kube-score
  • Interpréter les checks de fiabilité et de sécurité
  • Corriger un manifest et gérer les faux positifs
  • Bloquer un déploiement non conforme en CI/CD
  • Des manifests Kubernetes (Deployment, Service...) à analyser
  • Docker ou un binaire kube-score (aucun accès cluster requis)

kube-score fait de l'analyse statique : il lit du YAML (un fichier, un dossier, ou l'entrée standard) et n'a pas besoin d'accès au cluster. Pour chaque objet, il applique une série de checks et attribue un verdict par recommandation : [OK], [WARNING], [CRITICAL] ou [SKIPPED].

Sa valeur est de viser deux dimensions à la fois : la fiabilité (ressources, probes, réplicas, PodDisruptionBudget, anti-affinité) et la sécurité (tag d'image fixe, securityContext, NetworkPolicy). Il couvre 39 checks dans la version 1.20.0, dont une partie optionnelle.

Fenêtre de terminal
docker run --rm -v "$(pwd):/project" zegl/kube-score:latest score /project/deploy.yaml

Prenons un Deployment minimal, du genre qu'on écrit vite pour tester. Il passe kubectl apply sans broncher :

deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 1
selector:
matchLabels: { app: web }
template:
metadata:
labels: { app: web }
spec:
containers:
- name: web
image: nginx:latest

On le passe à kube-score via l'entrée standard (-) :

Fenêtre de terminal
kube-score score - < deploy.yaml
apps/v1/Deployment web
[CRITICAL] Container Image Tag
· web -> Image with latest tag
Using a fixed tag is recommended to avoid accidental upgrades
[CRITICAL] Container Resources
· web -> CPU/Memory request and limit is not set
[CRITICAL] Container Security Context User Group ID
[CRITICAL] Container Security Context ReadOnlyRootFilesystem
[CRITICAL] Container Ephemeral Storage Request and Limit
[CRITICAL] Pod NetworkPolicy
· The pod does not have a matching NetworkPolicy

Six recommandations [CRITICAL], et surtout : le programme sort avec le code 1. C'est le point clé pour la CI. Chaque ligne dit quoi corriger : tag d'image figé, ressources, contexte de sécurité, NetworkPolicy.

kube-score regroupe ses 39 checks autour de quelques intentions. Les plus fréquents :

Check (ID)Ce qu'il vérifieDimension
container-image-tagun tag fixe, jamais :latestsécurité / repro
container-resourcesrequests et limits CPU/mémoire définisfiabilité
container-security-context-*runAsNonRoot, readOnlyRootFilesystem, non privilegedsécurité
pod-probesprobes readiness et liveness présentes et différentesfiabilité
deployment-replicasau moins 2 réplicas (seuil configurable)fiabilité
pod-networkpolicyune NetworkPolicy cible le podsécurité
deployment-has-poddisruptionbudgetun PDB protège le Deploymentfiabilité

Améliorons le manifest avec tout ce qu'un Deployment sérieux devrait avoir : tag fixe, ressources, securityContext, probes distinctes, deux réplicas.

deploy.yaml (durci)
spec:
replicas: 2
template:
spec:
securityContext:
runAsNonRoot: true
containers:
- name: web
image: nginx:1.27.3-alpine
imagePullPolicy: IfNotPresent
resources:
requests: { cpu: "100m", memory: "64Mi" }
limits: { cpu: "200m", memory: "128Mi" }
securityContext:
readOnlyRootFilesystem: true
privileged: false
readinessProbe:
httpGet: { path: /, port: 80 }
livenessProbe:
httpGet: { path: /healthz, port: 80 }

Re-scannons. Le verdict s'améliore nettement, mais kube-score reste exigeant :

[CRITICAL] Ephemeral Storage request/limit is not set
[CRITICAL] The pod does not have a matching NetworkPolicy
[CRITICAL] The container is running with a low user ID (< 10000)
[CRITICAL] ImagePullPolicy is not set to Always
[CRITICAL] No matching PodDisruptionBudget was found
[WARNING] Deployment does not have a host podAntiAffinity set

C'est volontaire : kube-score pousse les standards de production (PDB, NetworkPolicy, anti-affinité, stockage éphémère borné, UID élevé). À vous de décider lesquels sont pertinents dans votre contexte, ce qui mène à la section suivante.

Certains checks sont opinionated et ne collent pas à tous les contextes. L'exemple classique : pod-networkpolicy exige une NetworkPolicy même si votre CNI ne les applique pas. kube-score offre deux leviers pour ne pas crouler sous le bruit.

Au niveau de la commande, ignorer un check globalement :

Fenêtre de terminal
kube-score score deploy.yaml --ignore-test pod-networkpolicy

Au niveau d'un objet précis, via une annotation dans le manifest :

metadata:
annotations:
kube-score/ignore: pod-networkpolicy,container-image-pull-policy

Le format se choisit avec --output-format : human (défaut, lisible), ci (une ligne par résultat, idéal pour les logs), json (structuré), sarif (pour le code scanning GitHub).

Fenêtre de terminal
kube-score score deploy.yaml --output-format ci
[OK] web apps/v1/Deployment
[CRITICAL] web apps/v1/Deployment: The pod does not have a matching NetworkPolicy
[SKIPPED] web apps/v1/Deployment: Skipped because container-cpu-requests-equal-limits is ignored

Côté code retour : kube-score sort avec 1 dès qu'un [CRITICAL] est présent. Pour échouer aussi sur les warnings, ajoutez --exit-one-on-warning. C'est ce comportement qui permet de bloquer un pipeline.

Le principe : laisser kube-score échouer le job par son code retour. Helm et Kustomize ne produisant pas de YAML statique, on les rend d'abord (helm template), puis on pipe vers kube-score.

Voici un workflow GitHub Actions qui scanne les manifests et remonte les résultats dans l'onglet Security (format SARIF), avec les actions épinglées par commit (SHA) comme l'exige la sécurité de la chaîne d'approvisionnement :

.github/workflows/kube-score.yml
name: kube-score
on:
pull_request:
paths: ['manifests/**']
permissions: {}
jobs:
scan:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write # upload SARIF
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- name: Analyser les manifests
run: |
docker run --rm -v "$PWD:/project" zegl/kube-score:latest \
score /project/manifests/*.yaml \
--output-format sarif > results.sarif
continue-on-error: true
- name: Publier dans le code scanning
uses: github/codeql-action/upload-sarif@dd903d2e4f5405488e5ef1422510ee31c8b32357 # v3
with:
sarif_file: results.sarif

kube-score n'est pas seul. Le choix dépend de ce que vous cherchez.

OutilPérimètreSe distingue par
kube-scorefiabilité + sécurité des manifestssimple, sans cluster, pédagogique
KubeLinter (Red Hat)lint statique, production-readinesschecks custom (templates)
Polaris (Fairwinds)policy enginedashboard + admission controller
kubesecsécurité uniquementscore numérique + API
Trivy (Aqua)vulnérabilités + config + secretssuite large, cluster live

En clair : kube-score est le bon point de départ, focalisé et lisible. Passez à KubeLinter ou Polaris si vous voulez des règles maison ou un contrôle à l'admission, et à Trivy pour couvrir aussi les vulnérabilités d'images. Les trois sont complémentaires de kube-score, pas redondants.

  • Analyse statique : kube-score ne voit pas l'état réel du cluster (un Polaris en admission ou trivy k8s le complètent).
  • YAML statique seulement : Helm/Kustomize doivent être rendus avant (helm template | kube-score score -).
  • Checks opinionated : certains (NetworkPolicy, imagePullPolicy: Always, pas de NodePort) peuvent générer des faux positifs selon le contexte, d'où --ignore-test.
  • Pas de règles personnalisées : on active/désactive les checks fournis, on n'en écrit pas (contrairement à KubeLinter/Polaris).
  • kube-score analyse les manifests sans cluster et vise fiabilité + sécurité (39 checks en 1.20).
  • Verdicts [OK] / [WARNING] / [CRITICAL] ; il sort en code 1 dès un [CRITICAL], d'où son usage en CI.
  • Les checks clés : tag fixe, resources, securityContext, probes, réplicas, NetworkPolicy, PDB.
  • Les checks opinionated se filtrent avec --ignore-test ou l'annotation kube-score/ignore, en documentant pourquoi.
  • En CI : docker run zegl/kube-score + format SARIF vers le code scanning, actions épinglées par SHA.
  • C'est un point de départ : KubeLinter/Polaris pour les règles custom, Trivy pour les vulnérabilités.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn