Checkov est le scanner open source d'infrastructure as code (IaC) maintenu par Prisma Cloud (Palo Alto Networks), sous licence Apache 2.0. Il lit vos fichiers Terraform, Kubernetes, Dockerfile, Ansible ou CloudFormation et signale les mauvaises configurations avant qu'elles soient déployées : bucket public, SSH ouvert au monde, conteneur privilégié. Cette leçon s'adresse à un DevOps qui veut le brancher en CI sans se noyer dans ses résultats.
Tout est mesuré sur Checkov 3.3.22 : 25 échecs sur quatre ressources Terraform, 22 sur un seul Deployment, et des secrets en clair qui passent sans alerte dans chacun des quatre fichiers d'exemple. Savoir ce que Checkov ne voit pas compte autant que savoir lire ce qu'il trouve.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Installer Checkov en version épinglée et lancer un premier scan
- Lire un résultat et séparer les vrais risques des règles de confort
- Repérer les angles morts, secrets compris, avant de s'y fier
- Faire échouer un job CI sur les règles choisies, pas sur la sévérité
- Gérer les faux positifs et écrire une règle maison qui se charge
- Produire la preuve de SOCLE-INT-VER-2, l'analyse de configuration IaC
Qu'est-ce que Checkov ?
Section intitulée « Qu'est-ce que Checkov ? »Checkov est un analyseur statique (SAST)
spécialisé dans l'infrastructure as code : il lit le code, sans rien déployer
ni interroger un cloud. Chaque règle (un « check ») porte un identifiant
stable, comme CKV_AWS_24, et vérifie une bonne pratique précise. Il peut
aussi relier des ressources entre elles grâce à une analyse en graphe :
les règles préfixées CKV2_ regardent par exemple si un bucket S3 a un
blocage d'accès public déclaré dans une autre ressource.
Combien de règles, et pour quels formats ?
Section intitulée « Combien de règles, et pour quels formats ? »La commande checkov --list de la version 3.3.22 recense 1361 identifiants
de règles distincts. Le chiffre de « plus de 800 » qui circule encore date
des versions 2. La répartition montre où porte l'effort : Terraform écrase
tout le reste, et un framework plus récent comme GitHub Actions n'a qu'une
poignée de règles.
| Framework | Règles (Checkov 3.3.22) |
|---|---|
| Terraform | 1144 |
| ARM / Bicep (Azure) | 173 / 167 |
| CloudFormation | 139 |
| Kubernetes | 119 |
| Ansible | 29 |
| Dockerfile | 28 |
| OpenAPI | 21 |
| Secrets | 18 |
| GitHub Actions | 8 |
| GitLab CI | 3 |
Une même règle peut servir plusieurs formats, d'où une somme supérieure au total. Pour les pipelines CI, ces chiffres disent l'essentiel : un workflow GitHub Actions se vérifie mieux avec des outils dédiés comme zizmor, vu dans la leçon sur la confiance implicite des pipelines.
Ce que Checkov ne prouve pas
Section intitulée « Ce que Checkov ne prouve pas »Un rapport Checkov vert ne prouve pas qu'une infrastructure est sûre. Il prouve que le code ne contient aucune des configurations que ses règles connaissent. Trois limites reviennent dans toute la leçon. Il ne voit que le code, pas l'état réel du cloud ni ce qu'un opérateur a modifié à la main. Il ne lit pas les vulnérabilités des paquets d'une image, travail de Trivy. Et sa détection de secrets, mesurée plus bas, laisse passer les mots de passe ordinaires.
Installer Checkov en version épinglée
Section intitulée « Installer Checkov en version épinglée »Checkov est un paquet Python : on l'installe avec pipx pour l'isoler du
reste du système, en fixant la version. L'image Docker officielle évite
d'installer Python, et se fige par digest : depuis l'incident de Trivy en
2026, un scanner se traite comme toute dépendance, jamais en latest.
# Installation isolée, version figéepipx install "checkov==3.3.22"checkov --version# 3.3.22
# Ou sans Python, par l'image figée par digestdocker run --rm -v "$PWD":/src -w /src \ bridgecrew/checkov:3.3.22@sha256:617c76e3f9b1f7907ebca9abb6b9d746844edcb48e9bd775e4692c69c1c6ac47 \ -d . --compact --quietLa sortie de checkov --version doit afficher exactement la version
demandée. Le paquet Homebrew existe aussi sur macOS, mais il suit la
dernière version publiée, ce qui ne convient pas à une CI reproductible.
Premier scan : un Terraform volontairement faux
Section intitulée « Premier scan : un Terraform volontairement faux »Le plus simple pour comprendre Checkov est de lui donner un fichier dont on
connaît les fautes. Celui-ci est valide pour Terraform : terraform validate l'accepte. Il contient pourtant quatre erreurs classiques, marquées
en commentaire, et un mot de passe en clair.
# ❌ Bucket S3 avec accès publicresource "aws_s3_bucket" "bad_bucket" { bucket = "factures-clients-prod" acl = "public-read" # Problème : bucket accessible publiquement}
# ❌ Instance EC2 sans IMDSv2resource "aws_instance" "bad_instance" { ami = "ami-0c55b159cbfafe1f0" instance_type = "t3.micro" # Pas de metadata_options : IMDSv1 reste actif, exploitable par SSRF}
# ❌ Security Group SSH ouvert au monderesource "aws_security_group" "bad_sg" { name = "allow-all-ssh" ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] # Problème : SSH ouvert à Internet }}
# ❌ RDS accessible publiquement avec mot de passe en clairresource "aws_db_instance" "bad_rds" { identifier = "facturation" engine = "mysql" instance_class = "db.t3.micro" username = "admin" password = "SuperSecret123!" # Problème : secret dans le code publicly_accessible = true # Problème : BDD exposée à Internet}Lancer le scan et réduire la sortie
Section intitulée « Lancer le scan et réduire la sortie »Deux options rendent la sortie lisible dans un terminal. --compact retire
l'extrait de code affiché sous chaque résultat, et --quiet masque les
règles réussies : sans elle, Checkov liste aussi chaque contrôle passé.
Le scan sort avec le code 1 dès qu'une règle échoue, ce qui suffit à
faire échouer un job CI.
$ checkov -d terraform --compact --quietterraform scan results:
Passed checks: 14, Failed checks: 25, Skipped checks: 0
Check: CKV_AWS_79: "Ensure Instance Metadata Service Version 1 is not enabled" FAILED for resource: aws_instance.bad_instance File: /main.tf:8-12Check: CKV_AWS_24: "Ensure no security groups allow ingress from 0.0.0.0:0 to port 22" FAILED for resource: aws_security_group.bad_sg File: /main.tf:15-23Check: CKV_AWS_17: "Ensure all data stored in RDS is not publicly accessible" FAILED for resource: aws_db_instance.bad_rds File: /main.tf:26-33Check: CKV_AWS_20: "S3 Bucket has an ACL defined which allows public READ access." FAILED for resource: aws_s3_bucket.bad_bucket File: /main.tf:2-5...$ echo $?1Les quatre erreurs visées sont trouvées, chacune par une règle nommée. Chaque
bloc porte aussi une ligne Guide: vers la page de remédiation de Prisma
Cloud, retirée ici pour la lisibilité.
Lire un résultat : risque réel ou règle de confort ?
Section intitulée « Lire un résultat : risque réel ou règle de confort ? »Sur 25 échecs, quatre seulement correspondent aux fautes visées. Les 21 autres
sont des bonnes pratiques que ce fichier n'aborde pas : réplication
inter-régions du bucket (CKV_AWS_144), Multi-AZ de la base
(CKV_AWS_157), journalisation, cycle de vie. Elles ne se valent pas : un
bucket public expose des données aujourd'hui, une réplication absente coûte
seulement en cas de sinistre régional. Le travail de lecture consiste à
classer, pas à tout corriger.
| Règle | Ce qu'elle vérifie | Risque si on l'ignore |
|---|---|---|
CKV_AWS_20 | ACL public-read sur un bucket | Données lisibles par tout Internet |
CKV_AWS_24 | SSH ouvert depuis 0.0.0.0/0 | Force brute, accès non autorisé |
CKV_AWS_17 | publicly_accessible = true sur RDS | Base exposée directement |
CKV_AWS_79 | IMDSv1 actif sur EC2 | Vol des identifiants de l'instance par SSRF |
CKV_AWS_144 | Réplication inter-régions | Perte en cas de panne régionale, pas d'exposition |
Le mot de passe en clair de la base, lui, ne déclenche aucune règle.
La détection de secrets cherche des formats connus et des chaînes à forte
entropie : SuperSecret123! ne ressemble à aucun des deux. C'est le
premier angle mort à retenir.
Kubernetes, Dockerfile, Ansible : ce que les règles voient
Section intitulée « Kubernetes, Dockerfile, Ansible : ce que les règles voient »Les autres formats suivent le même principe, avec un piège commun : un nombre élevé de règles réussies ne dit rien de la sécurité du fichier. Checkov applique tout son jeu de règles à chaque ressource, y compris les contrôles du plan de contrôle Kubernetes qui n'ont aucun sens pour un Deployment.
Un Deployment qui donne accès au nœud
Section intitulée « Un Deployment qui donne accès au nœud »Ce manifeste cumule les configurations qui offrent à un conteneur un accès complet à son nœud : réseau et processus de l'hôte partagés, mode privilégié, racine du système de fichiers montée. Il porte aussi un secret en variable d'environnement.
apiVersion: apps/v1kind: Deploymentmetadata: name: insecure-app namespace: default # ❌ Utiliser le namespace defaultspec: replicas: 1 selector: matchLabels: app: insecure-app template: metadata: labels: app: insecure-app spec: hostNetwork: true # ❌ Partage le réseau du host hostPID: true # ❌ Voit les processus du host containers: - name: app image: nginx:latest # ❌ Tag "latest" non reproductible securityContext: privileged: true # ❌ Conteneur privilégié = root sur le host env: - name: DB_PASSWORD value: "secret123" # ❌ Secret dans les variables d'env volumeMounts: - mountPath: /host name: host-volume volumes: - name: host-volume hostPath: path: / # ❌ Monte la racine du hostLe scan remonte 22 échecs pour 67 réussites, et les plus graves sont bien
là. Attention aux identifiants : hostPID déclenche CKV_K8S_17, pas
CKV_K8S_1, qui porte le même intitulé mais ne vise que les anciennes
PodSecurityPolicy, retirées de Kubernetes.
$ checkov -f k8s/deployment.yaml --compact --quietkubernetes scan results:
Passed checks: 67, Failed checks: 22, Skipped checks: 0
Check: CKV_K8S_17: "Containers should not share the host process ID namespace"Check: CKV_K8S_19: "Containers should not share the host network namespace"Check: CKV_K8S_16: "Container should not be privileged"Check: CKV_K8S_14: "Image Tag should be fixed - not latest or blank"Check: CKV_K8S_43: "Image should use digest"...Deux fautes du manifeste ne déclenchent pourtant aucune règle. Le montage
hostPath de la racine / passe : la seule règle proche, CKV_K8S_27,
ne vise que le socket Docker. Et DB_PASSWORD en clair dans env.value passe
aussi : CKV_K8S_35 ne concerne que les secrets Kubernetes injectés en
variables. Ces deux angles morts relèvent d'un contrôleur d'admission et
des Pod Security Standards (les trois niveaux de restriction que Kubernetes
sait imposer aux pods), vus dans le module sur les conteneurs.
Un Dockerfile mal construit
Section intitulée « Un Dockerfile mal construit »Les règles Dockerfile portent sur des choix de construction : image de
base flottante, instruction ADD, absence d'utilisateur non-root. Ce fichier
en réunit plusieurs, et cache une clé d'API dans un ENV, lisible par
quiconque récupère l'image.
# ❌ Tag "latest" : version non reproductibleFROM python:latest
# ❌ MAINTAINER déprécié (utiliser LABEL)MAINTAINER dev@example.com
WORKDIR /app
# ❌ ADD peut extraire des archives et télécharger depuis InternetADD https://example.com/config.tar.gz /app/ADD . /app/
RUN pip install -r requirements.txt
# ❌ Expose le port SSHEXPOSE 22 80
# ❌ Secret dans une variable d'environnement (visible dans l'image)ENV API_KEY=sk-secret-12345
# ❌ Pas de USER ni de HEALTHCHECKCMD ["python", "app.py"]Le scan donne 7 échecs. Les règles d'absence, comme CKV_DOCKER_3 qui
exige un USER, visent le fichier entier (Dockerfile. sans suffixe), faute
de ligne à désigner.
$ checkov -f docker/Dockerfile --compact --quietdockerfile scan results:
Passed checks: 26, Failed checks: 7, Skipped checks: 0
Check: CKV_DOCKER_7: "Ensure the base image uses a non latest version tag"Check: CKV_DOCKER_6: "Ensure that LABEL maintainer is used instead of MAINTAINER (deprecated)"Check: CKV_DOCKER_4: "Ensure that COPY is used instead of ADD in Dockerfiles"Check: CKV_DOCKER_4: "Ensure that COPY is used instead of ADD in Dockerfiles"Check: CKV_DOCKER_1: "Ensure port 22 is not exposed"Check: CKV_DOCKER_2: "Ensure that HEALTHCHECK instructions have been added to container images"Check: CKV_DOCKER_3: "Ensure that a user for the container has been created"La clé API_KEY=sk-secret-12345 n'apparaît nulle part. CKV_DOCKER_7 ne
se déclenche que sur latest : un tag versionné sans digest, comme
python:3.14, le satisfait. La leçon sur les
bonnes pratiques Dockerfile
couvre ce que ces règles laissent de côté.
Un playbook Ansible
Section intitulée « Un playbook Ansible »Le jeu de règles Ansible est court, 29 règles, centrées sur les options
qui désactivent une vérification. Ce playbook en contient deux, force
et validate_certs, plus un mode: "0777" et deux secrets en variables.
---- name: Configuration serveur web hosts: webservers become: true vars: # ❌ Mot de passe en clair dans le code db_password: "SuperSecret123!" api_key: "sk-1234567890abcdef"
tasks: - name: Install packages with force ansible.builtin.apt: name: nginx state: present force: true # ❌ Contourne la vérification de signature
- name: Download file ansible.builtin.get_url: url: https://example.com/config.tar.gz dest: /tmp/config.tar.gz validate_certs: false # ❌ Désactive la validation TLS
- name: Set insecure permissions ansible.builtin.file: path: /etc/app/config mode: "0777" # ❌ Permissions trop permissivesLe scan produit deux rapports pour un seul fichier : ansible pour les
modules et secrets pour le texte. La détection de secrets tourne sur tout
fichier qu'elle sait lire, quel que soit le framework.
$ checkov -f ansible/playbook.yml --compact --quietsecrets scan results:
Passed checks: 0, Failed checks: 1, Skipped checks: 0
Check: CKV_SECRET_6: "Base64 High Entropy String" File: /ansible/playbook.yml:8-9
ansible scan results:
Passed checks: 2, Failed checks: 2, Skipped checks: 0
Check: CKV_ANSIBLE_6: "Ensure that the force parameter is not used, as it disables signature validation ..."Check: CKV_ANSIBLE_2: "Ensure that certificate validation isn't disabled with get_url"Seule l'api_key, chaîne aléatoire, est trouvée. Le db_password
passe, et le mode: "0777" aussi : aucune des 29 règles Ansible ne lit la
valeur d'une permission. Ce contrôle reste à la relecture de code, ou à
une règle maison comme celles de la fin de cette leçon.
La détection de secrets a des angles morts
Section intitulée « La détection de secrets a des angles morts »Checkov embarque 18 règles de secrets : formats connus (CKV_SECRET_2 pour
une clé AWS AKIA…, CKV_SECRET_13 pour une clé privée, CKV_SECRET_14 pour
Slack) et deux règles d'entropie, en base64 (CKV_SECRET_6) et en
hexadécimal (CKV_SECRET_19). Ce mécanisme rate deux catégories, mesurées
sur la version 3.3.22.
La première est le mot de passe humain : SuperSecret123!, secret123 ou
sk-secret-12345 n'ont ni format connu ni entropie suffisante, et aucun des
quatre fichiers précédents ne les a signalés. La seconde est plus surprenante :
par défaut, Checkov ne lit les secrets que dans certains types de
fichiers. Une vraie clé AWS dans un credentials.ini, ou un jeton GitHub
dans un .env, passe sans alerte.
$ checkov -d sec --framework secrets --compact --quiet# aucun résultat : .ini et .env ne sont pas lus
$ checkov -d sec --framework secrets --compact --quiet --enable-secret-scan-all-filesPassed checks: 0, Failed checks: 3, Skipped checks: 0Check: CKV_SECRET_6: "Base64 High Entropy String" File: /.env:1-2Check: CKV_SECRET_2: "AWS Access Key" File: /credentials.ini:1-2Check: CKV_SECRET_2: "AWS Access Key" File: /credentials.ini:2-3Le même contenu renommé en config.yaml est trouvé sans l'option. La
conclusion pratique : Checkov ne remplace pas un détecteur de secrets
dédié comme gitleaks, lancé en pré-commit et en CI, vu dans la leçon sur
les secrets en CI/CD.
Faire échouer la CI sur les bonnes règles
Section intitulée « Faire échouer la CI sur les bonnes règles »Checkov sort en code 1 dès qu'une règle échoue et en code 0 sinon : sur un vieux projet, le premier job casse donc à coup sûr. Trois options règlent ce comportement, et elles ont été mesurées sur le Dockerfile précédent.
| Option | Effet | Code de sortie mesuré |
|---|---|---|
| aucune | Échec dès une règle en faute | 1 |
--soft-fail | Rapport complet, jamais d'échec | 0 |
--soft-fail-on CKV_DOCKER_2,CKV_DOCKER_3 | Ces deux règles ne bloquent plus, les autres si | 1 (5 autres échecs) |
--soft-fail --hard-fail-on CKV_DOCKER_8 | Seule la règle listée bloque | 0 (elle passe) |
Le couple --soft-fail et --hard-fail-on est le plus utile pour démarrer :
on bloque sur une liste courte de règles graves, comme CKV_AWS_20,
CKV_AWS_24 ou CKV_K8S_16, et on laisse le reste en rapport. On allonge la
liste à mesure que la dette baisse.
Un exemple GitHub Actions
Section intitulée « Un exemple GitHub Actions »L'action officielle bridgecrewio/checkov-action exécute Checkov dans son
image officielle. Elle se fige sur le SHA de son commit, comme toute
action : sa version v12.3128.0 exécute Checkov 3.3.22. Le rapport SARIF (format
standard de résultats d'analyse) part dans l'onglet Code Scanning du dépôt,
même quand le scan échoue, grâce à if: always().
name: checkov
on: pull_request: paths: - "infra/**"
permissions: {}
jobs: checkov: runs-on: ubuntu-24.04 permissions: contents: read security-events: write steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false
- name: Scanner l'IaC uses: bridgecrewio/checkov-action@cc0e17d456ef1713bbfd963ebac19dc776775cb2 # v12.3128.0 with: directory: infra/ framework: terraform output_format: cli,sarif output_file_path: console,results.sarif
- name: Publier dans Code Scanning if: always() uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 with: sarif_file: results.sarifCe workflow passe actionlint, zizmor 1.30.0 et poutine 1.1.6 sans
aucun constat. Une limite reste à connaître : l'action désigne son image par
tag (ghcr.io/bridgecrewio/checkov:3.3.22), pas par digest. Pour une
garantie complète, on lance l'image figée par digest dans un pas run.
Gérer les faux positifs
Section intitulée « Gérer les faux positifs »Une règle peut être fausse dans votre contexte : un bucket qui héberge un site public doit être public. Checkov offre trois mécanismes, du plus ciblé au plus large. Le premier, la suppression en ligne, est le seul qui reste attaché au code et passe en revue avec lui.
Supprimer une règle dans le code
Section intitulée « Supprimer une règle dans le code »Chaque format a sa syntaxe de commentaire, toujours suivie d'une
justification. Les trois formes suivantes ont été vérifiées : chaque scan
compte la règle en Skipped checks: 1 ou 2 au lieu d'un échec.
resource "aws_s3_bucket" "site" { # checkov:skip=CKV_AWS_20: site statique public par conception bucket = "site-vitrine" acl = "public-read"}apiVersion: v1kind: Podmetadata: name: test-pod namespace: recette annotations: checkov.io/skip1: CKV_K8S_40=UID imposé par l'image de testspec: containers: - name: app image: nginx:1.29.1@sha256:8adbdcb969e2676478ee2c7ad333956f0c8e0e4c5a7463f4611d7a2e7a7ff5dc# checkov:skip=CKV_DOCKER_2: la sonde de santé est portée par le manifeste KubernetesFROM ubuntu:24.04@sha256:008173c23f95b170204355c12626cb5a965d779a7e1283b09e9cffbb1bf33ca3# checkov:skip=CKV_DOCKER_4: l'archive doit être décompressée à la copieADD app.tar.gz /opt/app/RUN useradd --uid 1000 --create-home appuserUSER appuserSur Kubernetes, l'annotation se numérote (skip1, skip2…) pour en poser
plusieurs. En ligne de commande, --skip-check CKV_AWS_20,CKV_AWS_21 retire
des règles pour tout le scan, sans trace dans le code : à réserver aux règles
que l'équipe juge hors sujet partout.
Démarrer avec une baseline
Section intitulée « Démarrer avec une baseline »Sur un projet existant, --create-baseline enregistre les échecs du moment
dans un fichier .checkov.baseline, posé dans le dossier scanné. Les
scans suivants avec --baseline ne signalent plus que les nouveaux
échecs. Mesuré : après ajout d'un Security Group RDP ouvert au Terraform de
départ, le scan avec baseline ne remonte que ses 3 échecs, au lieu de 28.
checkov -d terraform --create-baselinecheckov -d terraform --baseline terraform/.checkov.baseline --compact --quietLa baseline fige une dette, elle ne la règle pas. On la versionne, et on la régénère seulement quand des corrections l'ont réduite.
Un fichier de configuration pour l'équipe
Section intitulée « Un fichier de configuration pour l'équipe »Plutôt que de répéter les options, un fichier .checkov.yaml posé dans le
dossier courant est chargé automatiquement, sans option. Mesuré : avec
skip-check: [CKV_DOCKER_2, CKV_DOCKER_3] dans ce fichier, un simple
checkov -d . tombe de 7 à 5 échecs. C'est pratique et piégeux à la fois,
comme le trivy.yaml de la leçon précédente : un fichier oublié dans un
dépôt filtre en silence le rapport.
directory: - infraframework: - terraform - kubernetes - dockerfileskip-check: - CKV_AWS_144 # réplication inter-régions : hors budget, décision du 2026-10-01compact: truequiet: trueChaque clé reprend une option de la ligne de commande sans le double tiret.
La commande checkov -d . --skip-check CKV_DOCKER_7 --create-config .checkov.yaml écrit ce fichier à partir des options du moment, et
--show-config affiche la configuration réellement appliquée. Évitez la clé
check: : renseignée, elle limite le scan aux seules règles listées.
Exporter les résultats
Section intitulée « Exporter les résultats »Checkov écrit plusieurs formats en un passage : cli, json, sarif,
junitxml, csv et cyclonedx, entre autres. Le comportement de
--output-file-path change selon ce qu'on lui donne, et c'est mesuré : une
liste de chemins, un par format, écrit des fichiers ; un seul
chemin pour plusieurs formats est traité comme un dossier, rempli de
results_json.json et results_sarif.sarif.
# Un fichier par format : console pour le cli, checkov.xml pour JUnitcheckov -d infra -o cli -o junitxml --output-file-path console,checkov.xml
# Un dossier pour plusieurs formatscheckov -d infra -o sarif -o json --output-file-path rapportsLe bloc summary du JSON suffit pour suivre un projet dans le temps. Son
champ parsing_errors mérite l'attention : un fichier que Checkov n'a pas su
lire n'est pas analysé, et ne compte pas comme un échec.
{ "passed": 26, "failed": 7, "skipped": 0, "parsing_errors": 0, "resource_count": 1, "checkov_version": "3.3.22"}Écrire une règle maison
Section intitulée « Écrire une règle maison »Les règles intégrées ignorent vos conventions internes : étiquette de
centre de coût obligatoire, types d'instance autorisés. Checkov accepte des
règles en YAML pour un attribut à vérifier, et en Python pour une
logique plus riche. Les deux se chargent avec --external-checks-dir.
En YAML : une étiquette obligatoire
Section intitulée « En YAML : une étiquette obligatoire »Le format YAML décrit une condition sur un attribut. Celle-ci exige une
étiquette cost-center sur chaque bucket S3 ; sur le Terraform de départ,
elle échoue sur aws_s3_bucket.bad_bucket, qui n'en porte pas.
metadata: id: "CKV2_ACME_1" name: "Ensure S3 buckets carry a cost-center tag" category: "GENERAL_SECURITY"
definition: cond_type: "attribute" resource_types: - "aws_s3_bucket" attribute: "tags.cost-center" operator: "exists"checkov -d terraform --external-checks-dir policies --check CKV2_ACME_1En Python, et le piège du __init__.py
Section intitulée « En Python, et le piège du __init__.py »Une règle Python hérite d'une classe de base et renvoie PASSED ou FAILED.
Celle-ci refuse les types d'instance hors liste. Un détail décide de tout,
mesuré sur la version 3.3.22 : sans fichier __init__.py dans le dossier,
la règle n'est pas chargée, et Checkov ne le dit pas. Le scan rend alors
zéro résultat, qu'on prend facilement pour un succès.
from checkov.common.models.enums import CheckCategories, CheckResultfrom checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
class EC2InstanceTypeCheck(BaseResourceCheck): def __init__(self): super().__init__( name="Ensure EC2 instances use approved instance types", id="CKV_ACME_1", categories=[CheckCategories.GENERAL_SECURITY], supported_resources=["aws_instance"], )
def scan_resource_conf(self, conf): # Types autorisés dans votre organisation autorises = ["t3.micro", "t3.small", "t3.medium"] instance_type = conf.get("instance_type", [None])[0] if instance_type in autorises: return CheckResult.PASSED return CheckResult.FAILED
check = EC2InstanceTypeCheck()touch checks/__init__.py # sans lui, la règle est ignorée en silencecheckov -d terraform --external-checks-dir checks --check CKV_ACME_1# Passed checks: 1 (t3.micro) ; une instance m5.4xlarge donne FAILEDPréfixez les identifiants par le nom de l'organisation (CKV_ACME_) pour
éviter toute collision avec une future règle officielle. Testez chaque règle
sur un fichier conforme et un fichier fautif : une règle qui ne voit
jamais d'échec n'a peut-être jamais été chargée.
À retenir
Section intitulée « À retenir »- Checkov lit le code d'infrastructure sans rien déployer : 1361 règles en 3.3.22, dont 1144 pour Terraform.
- On l'installe épinglé :
pipx install "checkov==3.3.22"ou l'image figée par digest. --compactretire le code,--quietretire les réussites ; le scan sort en code 1 au premier échec.- Un échec n'est pas un risque : on classe les résultats avant de corriger.
- Les secrets ordinaires passent, et les fichiers
.iniou.envne sont lus qu'avec--enable-secret-scan-all-files. - Sans clé d'API, pas de sévérité : on bloque avec
--soft-failet--hard-fail-onsur des règles nommées. - Un
.checkov.yamlest chargé automatiquement, et une règle Python sans__init__.pyest ignorée en silence. - La preuve attendue par SOCLE-INT-VER-2 est un rapport d'analyse de configuration IaC : le SARIF ou le JSON du job CI.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de cette leçon est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Score par domaine
Un domaine regroupe plusieurs guides et reçoit plusieurs questions : son score est plus fiable qu'un score par thème, qui porte souvent sur une seule question.
Bilan
Points forts
Aucun sujet réussi à 80 % sur au moins deux questions pour l’instant.
Points faibles
Aucun sujet sous le seuil de réussite.
À faire ensuite
Des indices pour retenter votre chance ?
Continuer le cours : IaC : des secrets Vault sans trace dans le state
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
FAQ : questions fréquentes
Section intitulée « FAQ : questions fréquentes »Les questions ci-dessous reprennent les doutes les plus courants sur Checkov : comparaison avec Trivy, intégration en CI, faux positifs et règles maison, avec la même version épinglée que la leçon.
CKV_AWS_24, CKV_K8S_16…).Ce qu'il couvre
La version 3.3.22 recense 1361 identifiants de règles (checkov --list), dont 1144 pour Terraform, 139 pour CloudFormation, 119 pour Kubernetes, 29 pour Ansible et 28 pour les Dockerfile.Ce qu'il ne fait pas
- Il ne voit pas l'état réel du cloud, seulement le code.
- Il ne cherche pas les CVE des paquets d'une image : c'est le rôle de Trivy ou Grype.
- Sa détection de secrets rate les mots de passe ordinaires.
checkov -d terraform --compact --quiet
Avec pipx, version figée
pipx install "checkov==3.3.22"
checkov --version
# 3.3.22
pipx isole Checkov dans son propre environnement Python, sans toucher au système.Avec Docker, image figée par digest
docker run --rm -v "$PWD":/src -w /src \
bridgecrew/checkov:3.3.22@sha256:617c76e3f9b1f7907ebca9abb6b9d746844edcb48e9bd775e4692c69c1c6ac47 \
-d . --compact --quiet
Pourquoi épingler
Un scanner s'exécute avec accès au code et souvent aux secrets de la CI. Depuis la compromission de Trivy en 2026, on le traite comme toute dépendance : version exacte, et digest pour une image. Homebrew installe la dernière version publiée, ce qui convient à un poste mais pas à une CI reproductible.Commandes de base
# Un dossier, sortie lisible
checkov -d terraform --compact --quiet
# Un seul fichier
checkov -f terraform/main.tf
# Limiter au framework Terraform
checkov -d . --framework terraform
Deux options à ne pas confondre
| Option | Effet |
|---|---|
--compact |
Retire l'extrait de code sous chaque résultat |
--quiet |
Masque les règles réussies |
Ce qu'on obtient
Sur un fichier de quatre ressources volontairement fautives, Checkov 3.3.22 rend 25 échecs : les quatre fautes visées (CKV_AWS_20, CKV_AWS_24, CKV_AWS_17, CKV_AWS_79) et 21 bonnes pratiques comme la réplication inter-régions. Il faut classer avant de corriger. Le mot de passe en clair de la base, lui, n'est pas signalé.Comparaison
| Critère | Checkov | Trivy |
|---|---|---|
| Éditeur | Prisma Cloud (Palo Alto) | Aqua Security |
| Configurations IaC | Cœur de l'outil, 1361 règles | Oui, moteur hérité de tfsec |
| CVE des images et dépendances | Non en open source | Oui |
| SBOM | Export CycloneDX des résultats | Génération et rescan |
| Règles maison | Python ou YAML | Rego |
Quand utiliser quoi
- Checkov quand l'infrastructure as code est le sujet principal et qu'on veut écrire ses propres règles simplement.
- Trivy pour un seul outil couvrant images, dépendances, secrets et configuration.
- Les deux pour croiser : deux moteurs ne ratent pas les mêmes choses.
Dans le code, avec une justification
resource "aws_s3_bucket" "site" {
# checkov:skip=CKV_AWS_20: site statique public par conception
bucket = "site-vitrine"
acl = "public-read"
}
metadata:
annotations:
checkov.io/skip1: CKV_K8S_40=UID imposé par l'image de test
# checkov:skip=CKV_DOCKER_2: la sonde de santé est portée par Kubernetes
La règle passe alors en Skipped checks au lieu d'un échec.En ligne de commande
checkov -d . --skip-check CKV_AWS_20,CKV_AWS_21
Réservez cette forme aux règles jugées hors sujet partout : elle ne laisse aucune trace dans le code.Sur un projet existant
--create-baseline enregistre les échecs du moment dans .checkov.baseline, et --baseline ne signale ensuite que les nouveaux.En YAML
metadata:
id: "CKV2_ACME_1"
name: "Ensure S3 buckets carry a cost-center tag"
category: "GENERAL_SECURITY"
definition:
cond_type: "attribute"
resource_types:
- "aws_s3_bucket"
attribute: "tags.cost-center"
operator: "exists"
checkov -d terraform --external-checks-dir policies --check CKV2_ACME_1
En Python
Une classe hérite deBaseResourceCheck et renvoie CheckResult.PASSED ou FAILED. Le dossier doit contenir un __init__.py : mesuré sur la version 3.3.22, sans lui la règle n'est pas chargée et le scan ne rend aucun résultat, sans erreur.Bonne pratique
Testez chaque règle sur un fichier conforme et un fichier fautif. Une règle qui ne voit jamais d'échec n'a peut-être jamais été chargée.Workflow
permissions: {}
jobs:
checkov:
runs-on: ubuntu-24.04
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: bridgecrewio/checkov-action@cc0e17d456ef1713bbfd963ebac19dc776775cb2 # v12.3128.0
with:
directory: infra/
output_format: cli,sarif
output_file_path: console,results.sarif
- if: always()
uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
with:
sarif_file: results.sarif
À savoir
- La version v12.3128.0 de l'action exécute Checkov 3.3.22, désignée par tag et non par digest.
- Ce workflow passe actionlint, zizmor et poutine sans constat.
- Les résultats apparaissent dans l'onglet Security, rubrique Code scanning.
Job GitLab CI
checkov:
stage: test
image:
name: bridgecrew/checkov:3.3.22@sha256:617c76e3f9b1f7907ebca9abb6b9d746844edcb48e9bd775e4692c69c1c6ac47
entrypoint: [""]
script:
- checkov -d infra -o cli -o junitxml --output-file-path console,checkov.xml --compact --quiet
artifacts:
when: always
reports:
junit: checkov.xml
Points clés
entrypoint: [""]laisse GitLab lancer son shell à la place de la commandecheckovde l'image.- Avec une liste de chemins,
--output-file-pathécrit un fichier par format ; avec un seul chemin pour plusieurs formats, il crée un dossier. - Le job échoue au premier échec. Pour bloquer seulement sur des règles graves :
--soft-fail --hard-fail-on CKV_AWS_20,CKV_AWS_24.
Ce qui a été mesuré
Sur un Dockerfile qui échoue sur 7 règles,checkov --skip-check LOW garde ses 7 échecs : sans clé d'API Prisma Cloud, Checkov ne connaît pas la sévérité de ses règles.Ce qui fonctionne sans clé
| Option | Effet |
|---|---|
--soft-fail |
Rapport complet, code de sortie 0 |
--soft-fail-on ID,ID |
Ces règles ne bloquent plus |
--hard-fail-on ID,ID |
Avec --soft-fail, seules ces règles bloquent |
Méthode conseillée
Commencez par une liste courte de règles graves en--hard-fail-on (bucket public, SSH ouvert, conteneur privilégié), et allongez-la à mesure que la dette baisse.Ce qu'il trouve
Des formats connus (CKV_SECRET_2 pour une clé AWS, CKV_SECRET_13 pour une clé privée) et des chaînes à forte entropie (CKV_SECRET_6, CKV_SECRET_19).Ce qu'il rate, mesuré sur la version 3.3.22
- Les mots de passe humains :
SuperSecret123!dans un Terraform,secret123dans un manifeste,API_KEY=sk-secret-12345dans un Dockerfile ne sont pas signalés. - Les fichiers
.iniet.env: une clé AWS danscredentials.inipasse, sauf avec l'option suivante.
checkov -d . --framework secrets --enable-secret-scan-all-files
Conséquence
Checkov complète un détecteur dédié comme gitleaks, lancé en pré-commit et en CI, il ne le remplace pas.Exemple
# .checkov.yaml
directory:
- infra
framework:
- terraform
- kubernetes
skip-check:
- CKV_AWS_144 # réplication inter-régions : hors budget
compact: true
quiet: true
Commandes utiles
# Écrire le fichier à partir des options du moment
checkov -d . --skip-check CKV_AWS_144 --create-config .checkov.yaml
# Voir ce qui est vraiment appliqué, et d'où cela vient
checkov -d . --show-config
Le piège
Le fichier est chargé sans option : un.checkov.yaml oublié dans un dépôt peut retirer des règles en silence. Mesuré : deux lignes de skip-check font passer un Dockerfile de 7 à 5 échecs. Évitez aussi la clé check:, qui limite le scan aux seules règles listées.D'où vient le volume
Sur un Terraform de quatre ressources, 25 échecs pour quatre fautes réelles ; sur un seul Deployment Kubernetes, 22 échecs. Une partie relève de la sécurité (bucket public, conteneur privilégié), une autre du confort d'exploitation (Multi-AZ, sondes, limites de ressources).Comment réduire le bruit
| Situation | Réponse |
|---|---|
| Règle fausse dans votre contexte | checkov:skip= avec une justification |
| Règle hors sujet partout | skip-check dans .checkov.yaml, avec la décision en commentaire |
| Vieux projet | --create-baseline, puis --baseline |
| Fichier non lu | Vérifier parsing_errors dans le JSON |
Ce qu'il ne faut pas faire
Tout passer en--soft-fail sans liste --hard-fail-on : le scan ne bloque alors plus rien, et plus personne ne lit le rapport.