Une image Docker est constituée d'une pile de couches, qui sont des ensembles immuables et en lecture seule de modifications du système de fichiers superposés. Un système d'exploitation de base se trouve en bas, suivi des paquets nécessaires à son exécution, puis de votre propre code au sommet. Sécuriser des images Docker signifie contrôler leur contenu et veiller à leur correction après leur déploiement.
La plupart des vulnérabilités d'un conteneur proviennent des paquets et bibliothèques open source inclus par défaut. Certains éléments, comme cURL ou un shell, ne seront peut-être jamais appelés par votre application une fois le conteneur en cours d'exécution, et peuvent donc être retirés de l'image. D'autres, comme glibc, sont indispensables au fonctionnement de votre application et ne peuvent être supprimés. Le reste des vulnérabilités résulte généralement d'une erreur humaine, telle qu'un secret intégré dans une couche ou un conteneur laissé en cours d'exécution avec des privilèges root.
Cet article aborde l'origine des risques liés à une image Docker, explique pourquoi maintenir des images durcies relève de la gestion des vulnérabilités, présente les trois méthodes utilisées par les outils pour corriger une image de base, et montre comment Aikido durcit et corrige les images que vous utilisez déjà.
{{cta}}
TL;DR
Sécuriser des images Docker implique de supprimer les paquets inutilisés et de corriger les vulnérabilités dans ce qui subsiste. L'élimination des paquets superflus ne supprime que les vulnérabilités des éléments dont vous n'avez pas besoin. Un paquet vulnérable dont dépend réellement votre application nécessite toujours un correctif, et même une image minimaliste continue d'accumuler de nouvelles vulnérabilités. De plus, l'adoption d'images durcies implique souvent de migrer vers une autre distribution et de se mettre à jour selon le rythme d'un tiers. Aikido propose de nouvelles versions corrigées des mêmes images de base, livrées via PR. Si vous avez épinglé une version, cela vous permet de conserver cette version sans introduction de modifications cassantes ni bascule vers une nouvelle image.
D'où proviennent les risques d'une image Docker
Le FROM Cette ligne est la première instruction d'un fichier Dockerfile, qui désigne l'image de base sur laquelle vous construisez votre application. La ligne FROM node:24 définit l'image officielle Node.js 24 comme base, laquelle intègre le runtime Node.js ainsi qu'un système Debian complet en arrière-plan. Cela inclut un shell, un gestionnaire de paquets et des bibliothèques système, chacun pouvant porter des vulnérabilités dont vous héritez avant même d'écrire la moindre ligne de votre propre code.
Chaque instruction d'un fichier Dockerfile ajoute une couche par-dessus la précédente, et les couches sont immuables. Supprimer un élément dans une couche ultérieure ne fait que le masquer, de sorte que tout ce que l'image de base contenait y demeure, que votre application l'utilise ou non. Votre application ne fait appel à la grande majorité de ce qui est inclus dans la base, mais chaque paquet présent constitue une surface d'attaque potentielle.
Par exemple, la CVE-2023-4911 (« Looney Tunables ») était une faille d'élévation de privilèges locale dans le chargeur dynamique de glibc, un composant présent dans la couche de base de presque toutes les images Linux grand public. glibc était fourni avec la distribution et tout conteneur bâti sur une base affectée en héritait.
Différentes bases, différents risques
Toutes les images de base n'embarquent pas la même quantité de composants. Une image de distribution complète fournit bien plus que ce dont votre application a besoin, y compris un shell et un gestionnaire de paquets qu'elle n'utilisera probablement jamais. Une variante « slim » en réduit une partie. Une image « distroless » supprime totalement le shell et le gestionnaire de paquets pour ne conserver que le strict nécessaire au runtime. Alpine est conçue pour être compacte et, étant basée sur musl plutôt que sur glibc, elle n'a même pas été exposée à Looney Tunables.
Maintenir des images durcies relève de la gestion des vulnérabilités
Une image durcie est propre le jour de sa création, mais se dégrade avec le temps à mesure que de nouvelles vulnérabilités sont découvertes dans les paquets qu'elle contient. Pour la garder sécurisée, il faut considérer l'image comme un élément à réévaluer face aux nouvelles divulgations et à corriger en continu. La méthode manuelle consiste à suivre les divulgations pour chaque paquet de chaque image de base, puis à rétroporter ou appliquer chaque correctif à la main.
Fixer une version de confiance a du sens lorsque vous l'avez réellement testée et que vous souhaitez continuer à l'utiliser, mais vous devez tout de même surveiller les nouvelles divulgations. Une image épinglée et oubliée accumulera les vulnérabilités nouvellement découvertes. Si cette image atteint sa fin de vie (EOL) et cesse de recevoir des correctifs en amont, la liste de ses failles connues et non corrigées s'allonge. Par exemple, Node.js 20 a atteint sa fin de vie le 30 avril 2026 ; un conteneur toujours épinglé sur node:20 continuera de s'exécuter, mais chaque vulnérabilité divulguée pour cette branche depuis cette date restera sans correctif et sans mise à jour.
L'instinct inverse, qui consiste à se ruer systématiquement sur la toute dernière version, pose tout autant de problèmes. Par exemple, la porte dérobée de xz-utils concerne une bibliothèque de compression intégrée à la plupart des images de base Linux. Elle était présente dans deux versions récentes bien précises, les versions 5.6.0 et 5.6.1, tandis que les équipes restées sur la branche plus ancienne 5.4 n'ont jamais été exposées. Par la suite, la recommandation de la CISA a été de rétrograder la version, et non de la mettre à jour.
Ce qui permet réellement de rester en sécurité, c'est de prendre des décisions éclairées concernant les versions que vous exécutez. Prenons l'exemple d'une équipe qui fixe debian:bookworm, documente son choix par rapport à la dernière version parce qu'elle a été testée et qu'elle est stable, et la vérifie face aux nouvelles divulgations au fur et à mesure. Lorsqu'une nouvelle CVE est publiée sur un paquet de cette image, elle sait déjà qu'elle l'utilise et pourquoi. Cela lui permet de mesurer l'exposition réelle par rapport au coût d'un changement.
Comment sécuriser les images Docker
Réduire la surface d'attaque
Partez d'une image de base minimale ou pré-durcie. L'image de base détermine une grande partie de ce que vous héritez, il s'agit donc de votre choix le plus stratégique. (Abordé plus en détail dans la section suivante)
Utilisez des builds multi-stages pour éviter d'inclure les outils de compilation dans l'image finale. La construction de l'image intègre généralement un compilateur, des en-têtes de développement et un gestionnaire de paquets pour compiler votre application et installer ses dépendances. Dans un build à étape unique, tout cela reste inclus dans l'image finale, même si l'application en cours d'exécution ne l'utilise jamais. Un build multi-stages produit l'artefact lors d'une étape préliminaire et ne copie que celui-ci dans une étape finale propre, évitant ainsi d'embarquer les outils de compilation.
Supprimez les paquets dont l'application en cours d'exécution n'a pas besoin. Vous n'avez probablement pas besoin d'un shell, car la plupart des applications lancent leur processus directement et n'en appellent aucun à l'exécution. Des utilitaires comme cURL ou wget sont utiles lors de la phase de build, mais vous n'en avez probablement pas besoin en production, puisque votre application effectue ses appels réseau via ses propres bibliothèques. De plus, tout ce que cURL a téléchargé pendant le build est déjà inclus dans l'image au moment de sa livraison, il n'y a donc rien de plus à récupérer.
Configurer correctement les permissions
Exécutez le conteneur en tant qu'utilisateur non root. Si un attaquant parvient à exécuter du code dans votre application, il hérite des privilèges du compte sous lequel le conteneur s'exécute. L'utilisation d'un utilisateur non root réduit l'impact potentiel d'une intrusion.
Utilisez un système de fichiers racine en lecture seule. Cela empêche un attaquant déjà infiltré d'écrire des fichiers, de déposer des outils ou de modifier le conteneur au moment de l'exécution. Tout élément nécessitant impérativement des droits d'écriture peut disposer d'un montage inscriptible spécifique.
Retirez les capacités Linux superflues. Les conteneurs démarrent avec un ensemble de capacités du noyau que la plupart des applications n'utilisent jamais. CAP_NET_RAW, par exemple, permet à un processus de forger des paquets réseau et est activé par défaut, mais une application web typique n'en a jamais besoin, tandis qu'un attaquant qui s'infiltre pourrait l'utiliser pour usurper du trafic sur votre réseau. Supprimez celles dont vous n'avez pas besoin et ne rajoutez que le strict nécessaire. Supprimer ces capacités (et ne réintégrer que ce qui est utile) ferme la porte aux opérations privilégiées qu'un attaquant pourrait autrement exploiter.
Empêchez les secrets et les fichiers superflus de s'infiltrer dans l'image
Ne laissez aucun secret dans les couches. Un secret intégré via ARG ou COPY reste dans l'historique de l'image même si une couche ultérieure le supprime, et quiconque extrait l'image peut décompresser les couches et le lire. Utilisez des montages de secrets ou montages SSH pour exposer un secret à une seule étape de compilation sans l'écrire dans une couche.
Éviter d'inclure des secrets dans les couches n'est que la moitié du travail. Le conteneur en cours d'exécution a toujours besoin de la valeur, alors injectez-la au moment de l'exécution à partir d'un gestionnaire de secrets dédié (Vault, un gestionnaire de secrets cloud ou les secrets Kubernetes) monté sous forme de fichier ou injecté dans l'environnement, et faites-le pivoter régulièrement plutôt que d'intégrer des identifiants à longue durée de vie n'importe où.
Utilisez un fichier .dockerignore . Il contrôle ce qui entre dans le contexte de build en premier lieu, de sorte que .git, les configurations locales et les identifiants égarés ne soient jamais copiés dans l'image par une instruction COPY instruction.
Épinglez avec précaution
Épinglez l'image de base par condensé (digest) plutôt que par tag. FROM node:24 se résout à nouveau au fil du temps, ce qui signifie que deux builds espacés d'un mois peuvent extraire des images différentes, et qu'une image de base compromise peut s'immiscer discrètement. L'épinglage par condensé (@sha256:...) rend l'image de base déterministe, garantissant que vous construisez exactement l'image que vous avez testée. Sachez que si votre modèle de correctifs déploie des corrections sous forme de nouvelles images, un condensé épinglé retient également ces corrections. Si vous pouvez en revanche obtenir une version corrigée de la même version épinglée, vous évitez ce problème tout en restant sécurisé.
Ne vous fiez pas à latest. Certains pensent qu'il s'agit de la version la plus récente et la plus stable, mais dans Docker, c'est simplement l'étiquette par défaut appliquée à la dernière image poussée sans tag de version explicite. Elle peut pointer vers une image plus ancienne que prévu et changer à votre insu entre deux builds.
Vérifiez et maintenez
Générez un SBOM pour chaque image. Un Software Bill of Materials constitue l'inventaire complet du contenu de l'image, incluant chaque paquet et chaque version. C'est ce qui vous permet de répondre à la question « sommes-nous concernés ? » dès qu'une nouvelle vulnérabilité est rendue publique.
Signez chaque image lors de sa construction et vérifiez cette signature avant son exécution à l'aide d'un contrôleur d'admission qui rejette tout élément non signé. Cette chaîne empêche une image altérée ou non approuvée d'atteindre la production, même si un tiers parvient à s'introduire dans votre registre.
Considérez les conteneurs en cours d'exécution comme immuables. Une fois qu'une image est déployée, ne modifiez ni ne reconfigurez le conteneur actif. Construisez une nouvelle image, testez-la et redéployez-la. Ce qui s'exécute correspond alors toujours à ce que vous avez construit, testé et signé, ce qui élimine la dérive de configuration et rend un retour en arrière aussi simple que le redéploiement de l'image précédente.
Vérifiez les images en continu. Une image analysée comme propre la semaine dernière peut présenter une vulnérabilité critique aujourd'hui, car de nouvelles failles sont découvertes quotidiennement pour des paquets qu'elle contient déjà. Une simple vérification au moment du build ne suffit donc pas.
Trois façons de maintenir une image de base sécurisée
Maintenir une image de base sécurisée à mesure que de nouvelles vulnérabilités sont découvertes est une tâche continue, et il existe trois façons de l'aborder.
Le faire soi-même
Maintenez votre propre base sécurisée. Choisissez une image minimale, supprimez ce dont vous n'avez pas besoin et reconstruisez-la chaque fois qu'un paquet inclus présente une vulnérabilité. Vous conservez un contrôle total, mais cela demande un travail et une maintenance continus. Vous devez suivre les publications de vulnérabilités pour chaque paquet de la base et rétroporter (backporter) ou mettre à jour chaque correctif manuellement. Multipliez cela par le nombre de bases pour chaque service, et cela empiète sur tout le reste que vous pourriez développer.
Passer à la distribution reconstruite d'un fournisseur
Certaines plateformes proposent des images sécurisées reconstruites sur leur propre distribution. Vous migrez vos services vers leur base, effectuez de nouveaux tests de régression, puis dépendez de leur cycle de publication, en adoptant un nouveau digest à chaque correctif. Cela entraîne deux coûts. La migration elle-même peut perturber tout ce sur quoi votre application comptait et que le fournisseur a supprimé. Et rester à jour implique le même piège des mises à niveau que rencontrent toutes les mises à jour de dépendances, où une nouvelle version majeure peut modifier les chemins des paquets, changer les valeurs par défaut et casser un Dockerfile fonctionnel. Si vous épinglez un digest pour des raisons de stabilité, vous ne bénéficiez pas des correctifs mêmes qui vous ont poussé à adopter l'outil.
Laisser un outil corriger la base que vous utilisez déjà
Certains fournisseurs vous permettent de conserver votre version en place en fournissant des builds corrigés de cette même version, au lieu de vous faire basculer vers une nouvelle image. Vous obtenez un nouveau build de la même version avec le CVE corrigé, que vous adoptez en l'examinant et en le fusionnant comme n'importe quel autre changement, sans avoir à modifier l'image en cours d'exécution. De cette façon, vous restez sur la version que vous avez déjà testée tout en éliminant la vulnérabilité.
Comment Aikido sécurise les images Docker
Aikido Security fournit de nouveaux builds corrigés pour les mêmes versions d'images de base que vous utilisez déjà.

Aikido Images est un registre de plus de 2 000 images de remplacement direct (« drop-in ») dans lesquelles les vulnérabilités critiques et de haute sévérité connues de la base sont déjà corrigées. Chacune d'elles est reconstruite, corrigée, optimisée et sécurisée lors du build, ce qui vous offre une surface d'attaque réduite et des configurations par défaut durcies sur la base que vous utilisez déjà.
Là où un outil de distribution reconstruite déploie le correctif sous la forme d'une nouvelle image vers laquelle vous devez migrer, Aikido rétroporte (backporte) le correctif sur la version que vous avez épinglée. L'outil récupère le correctif de la version plus récente et l'applique à celle que vous utilisez déjà, de sorte que le changement reste minime et que l'image se comporte exactement comme avant. Lorsqu'un rétroportage propre n'est pas possible, Aikido met à niveau ou reconstruit le composant à la place. Le remplacement est une opération transparente proposée par AutoFix sous forme de pull request, et chaque téléchargement depuis docker.aikido.io est fourni avec un SBOM, un rapport VEX et une provenance SLSA.
L'outil continue de corriger les versions après que l'amont a cessé de les prendre en charge, y compris les bases arrivées en fin de vie (EOL). Vous pouvez ainsi conserver une ancienne version sans traîner ses failles connues et éviter d'avoir à effectuer une mise à niveau uniquement pour rester couvert.
Une part croissante des correctifs réels appliqués aux paquets ne se voit attribuer aucun CVE. Par conséquent, si vous ou vos outils ne lisez que la base de données des CVE, vous passez à côté de vulnérabilités. La correction d'Aikido est en partie alimentée par Aikido Intel, qui analyse les journaux de modifications (changelogs) et l'historique des commits en amont pour détecter les vulnérabilités qui ont été discrètement corrigées en amont sans identifiant CVE. Ainsi, votre couverture ne se limite pas à ce que les bases de données publiques ont eu le temps de documenter.
Les paquets au niveau de l'application pour npm, PyPI, Maven et Go sont corrigés directement sur place via Aikido Libraries, en appliquant la même approche de rétroportage que pour vos dépendances. Et Aikido Container Image Scanning recherche les paquets de système d'exploitation vulnérables, les dépendances, les runtimes obsolètes, les malwares et les risques liés aux licences dans les images de base, les commandes Dockerfile et les charges de travail Kubernetes, afin qu'une anomalie soit toujours présentée avec son contexte de code et de cloud.
L'équipe à l'origine de ces images a rejoint Aikido à la suite de l'acquisition de Root, l'entreprise qui a créé SlimToolkit (anciennement DockerSlim), l'un des outils open source de durcissement d'images les plus utilisés. Le durcissement d'images est le domaine par lequel cette équipe a commencé, et l'outil reste gratuit et ouvert à tous.
{{walkthrough}}
FAQ
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "TechArticle",
"@id": "https://www.aikido.dev/blog/securing-docker-images#article",
"isPartOf": { "@id": "https://www.aikido.dev/blog/securing-docker-images#webpage" },
"mainEntityOfPage": { "@id": "https://www.aikido.dev/blog/securing-docker-images#webpage" },
"headline": "Securing Docker images: harden, patch, and maintain them",
"description": "Most of a container's vulnerabilities come from the base image. How to harden Docker images, why hardening is ongoing, and how to patch the base you already run.",
"datePublished": "2026-08-28",
"dateModified": "2026-08-28",
"wordCount": 1650,
"timeRequired": "PT8M",
"inLanguage": "en-US",
"author": { "@id": "https://www.aikido.dev/authors/nicholas-thomson#person" },
"publisher": { "@id": "https://www.aikido.dev/#organization" },
"image": { "@id": "https://www.aikido.dev/blog/securing-docker-images#primaryimage" },
"articleSection": "DevSec Tools & Comparisons",
"keywords": [
"securing Docker images",
"Docker image security",
"container image hardening",
"base image vulnerabilities",
"distroless images",
"backporting CVE fixes",
"container vulnerability management",
"non-root container",
"multi-stage builds",
"SBOM"
],
"about": [
{ "@type": "Thing", "name": "Docker image security" },
{ "@type": "Thing", "name": "Container image hardening" },
{ "@type": "Thing", "name": "Vulnerability management" }
],
"mentions": [
{ "@type": "SoftwareApplication", "name": "Docker", "applicationCategory": "DeveloperApplication" },
{ "@type": "SoftwareApplication", "name": "Aikido Images", "applicationCategory": "SecurityApplication", "url": "https://www.aikido.dev/cloud/hardened-images" },
{ "@type": "SoftwareApplication", "name": "Aikido Libraries", "applicationCategory": "SecurityApplication" },
{ "@type": "Thing", "name": "Alpine Linux" },
{ "@type": "Thing", "name": "Debian" },
{ "@type": "Thing", "name": "glibc" },
{ "@type": "Thing", "name": "Node.js" },
{ "@type": "Thing", "name": "SBOM" },
{ "@type": "Thing", "name": "SLSA provenance" },
{ "@type": "Thing", "name": "VEX" },
{ "@type": "Thing", "name": "CVE-2023-4911", "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-4911" },
{ "@type": "Thing", "name": "CVE-2025-4373" }
],
"speakable": {
"@type": "SpeakableSpecification",
"cssSelector": ["h1", "h2"]
}
},
{
"@type": "WebPage",
"@id": "https://www.aikido.dev/blog/securing-docker-images#webpage",
"url": "https://www.aikido.dev/blog/securing-docker-images",
"name": "Securing Docker images: harden, patch, and maintain them",
"description": "Most of a container's vulnerabilities come from the base image. How to harden Docker images, why hardening is ongoing, and how to patch the base you already run.",
"inLanguage": "en-US",
"isPartOf": { "@id": "https://www.aikido.dev/#website" },
"primaryImageOfPage": { "@id": "https://www.aikido.dev/blog/securing-docker-images#primaryimage" },
"breadcrumb": { "@id": "https://www.aikido.dev/blog/securing-docker-images#breadcrumb" },
"datePublished": "2026-08-28",
"dateModified": "2026-08-28"
},
{
"@type": "ImageObject",
"@id": "https://www.aikido.dev/blog/securing-docker-images#primaryimage",
"url": "https://www.aikido.dev/blog/securing-docker-images/hero.png",
"caption": "Securing Docker images"
},
{
"@type": "BreadcrumbList",
"@id": "https://www.aikido.dev/blog/securing-docker-images#breadcrumb",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://www.aikido.dev" },
{ "@type": "ListItem", "position": 2, "name": "Blog", "item": "https://www.aikido.dev/blog" },
{ "@type": "ListItem", "position": 3, "name": "Securing Docker images", "item": "https://www.aikido.dev/blog/securing-docker-images" }
]
},
{
"@type": "WebSite",
"@id": "https://www.aikido.dev/#website",
"url": "https://www.aikido.dev",
"name": "Aikido Security",
"publisher": { "@id": "https://www.aikido.dev/#organization" },
"inLanguage": "en-US"
},
{
"@type": "Organization",
"@id": "https://www.aikido.dev/#organization",
"name": "Aikido Security",
"url": "https://www.aikido.dev",
"logo": {
"@type": "ImageObject",
"url": "https://www.aikido.dev/logo.png"
},
"sameAs": [
"https://www.linkedin.com/company/aikido-security",
"https://x.com/AikidoSecurity"
]
},
{
"@type": "Person",
"@id": "https://www.aikido.dev/authors/nicholas-thomson#person",
"name": "Nicholas Thomson",
"url": "https://www.aikido.dev/authors/nicholas-thomson",
"jobTitle": "Senior SEO & Growth Lead",
"worksFor": { "@id": "https://www.aikido.dev/#organization" },
"sameAs": [
"https://www.linkedin.com/in/nicholas-gray-thomson/"
]
},
{
"@type": "FAQPage",
"@id": "https://www.aikido.dev/blog/securing-docker-images#faq",
"isPartOf": { "@id": "https://www.aikido.dev/blog/securing-docker-images#webpage" },
"mainEntity": [
{
"@type": "Question",
"name": "What is the most important step to secure a Docker image?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Choosing a small base image. Most of a container's vulnerabilities come from the OS packages the base ships, not the code you wrote, so a smaller base means fewer inherited flaws before you add anything of your own. A distroless or minimal base drops whole classes of vulnerabilities that a full distro image would drag in."
}
},
{
"@type": "Question",
"name": "Should Docker containers run as root?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No, unless something genuinely requires it. If an attacker gets code execution in your app, they inherit whatever privileges the container runs as, and root in the container plus a container escape can mean root on the host. Set a dedicated non-root user in your Dockerfile and drop the Linux capabilities the app never uses."
}
},
{
"@type": "Question",
"name": "What is the difference between a minimal image and a hardened image?",
"acceptedAnswer": {
"@type": "Answer",
"text": "A minimal image ships less, stripping out shells, package managers, and libraries the app doesn't need. A hardened image starts from a minimal base and goes further, applying patched package versions and secure defaults like non-root execution. Minimal shrinks the attack surface, and hardened shrinks it and locks down what's left."
}
},
{
"@type": "Question",
"name": "Do I have to migrate to a new distro to harden my base image?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No. Some hardening tools rebuild images on their own distribution, which means migrating every service and re-testing for breakage. The alternative is to keep the distro and major version you already run and backport fixes to that exact version, which is how Aikido Images works, so you get the patch without the migration."
}
},
{
"@type": "Question",
"name": "Why does a hardened image become vulnerable again over time?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Because new vulnerabilities are disclosed against packages already inside it. Nothing in the image changed, but the list of known flaws in its packages keeps growing. Hardening is an ongoing job rather than a one-time pass."
}
},
{
"@type": "Question",
"name": "Can a secret end up inside a Docker image by accident?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Yes, and it is a common mistake. A secret pulled in with ARG or COPY stays in the image history even if a later layer deletes it, so anyone who pulls the image can unpack the layers and read it. Use build-time secret mounts during the build, and inject runtime secrets from a secrets manager rather than baking them into the image."
}
}
]
}
]
}
</script>