Site icon

Securiser une image Docker : hardening, non-root et scan de vulnerabilites

DOCKER · SÉCURITÉ · DEVOPS

Conteneurs non-root, hardening du Dockerfile, scan de vulnerabilites avec Trivy : un guide operationnel pour renforcer la securite de vos images Docker en production.

Pourquoi securiser ses images Docker

Sécuriser une image Docker : les piliers de la docker container security

Docker simplifie le deploiement, mais une image mal configuree est une porte ouverte pour les attaquants. Selon les rapports de securite, les conteneurs compromises representent une part croissante des incidents : images de base obsoletes, processus root a l’interieur du conteneur, secrets en clair dans le Dockerfile…

La docker container security repose sur trois piliers :

💡

A retenir

La securite des conteneurs ne remplace pas celle de l’hote. Un noyau Linux a jour, un firewall actif et une segmentation reseau restent indispensables.

Si vous debutez avec la construction d’images securisees, notre article sur la creation d’une image Docker PHP 8.4 non-root avec Composer et Node 24 est un excellent point de depart concret.

Executer un conteneur en utilisateur non-root

Par defaut, Docker execute les processus en tant que root a l’interieur du conteneur. Si un attaquant reussit a exploiter une vulnerabilite dans votre application, il obtient les privileges root dans le conteneur, ce qui augmente considerablement l’impact de l’attaque.

Creer un utilisateur dedie dans le Dockerfile

FROM python:3.12-slim AS base

# Installer les dependances systeme
RUN apt-get update \
    && apt-get install -y --no-install-recommends curl \
    && rm -rf /var/lib/apt/lists/*

# Creer un utilisateur non-root
RUN groupadd -r appuser && useradd -r -g appuser -d /app -s /sbin/nologin appuser

# Creer le repertoire et donner les droits
WORKDIR /app
COPY --chown=appuser:appuser requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY --chown=appuser:appuser . .

# Basculer vers l'utilisateur non-root
USER appuser

EXPOSE 8000

CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]

Forcer le non-root dans Docker Compose

services:
  web:
    image: mon-app:latest
    user: "1000:1000"
    read_only: true
    tmpfs:
      - /tmp
      - /run
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true

Astuce

Utilisez user: "1000:1000" dans docker-compose.yml pour forcer un utilisateur non-root meme si l’image ne le specifie pas. C’est un filet de securite supplementaire.

Hardening du Dockerfile : les bonnes pratiques

Les dockerfile best practices vont au-dela du simple USER non-root. Voici les regles essentielles pour un Dockerfile securise.

Utiliser une image de base officielle et legeres

Privilegiez les variantes -slim ou -alpine des images officielles. Moins de packages signifie moins de vulnerabilites.

# Bien : image slim
FROM node:22-slim

# Mieux si compatible : image alpine
FROM node:22-alpine

# A eviter : image complete avec outils inutiles
FROM node:22

Piner les versions des images de base

# Eviter : tag flottant, la version change
FROM python:3.12

# Preferer : version pinee
FROM python:3.12.3-slim
⚠️

Attention

Les tags flottants comme latest ou python:3.12 peuvent pointer vers une image differente a chaque build. Cela rend les deploiements non reproductibles et peut introduire des vulnerabilites inattendues.

Multi-stage build pour reduire la surface d’attaque

# Stage 1 : build
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

# Stage 2 : production (image finale minimaliste)
FROM node:22-alpine AS production
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=builder --chown=appuser:appgroup /app/package.json ./
USER appuser
EXPOSE 3000
CMD ["node", "dist/server.js"]

Avec le multi-stage build, l’image finale ne contient ni les outils de compilation, ni les sources, ni les devDependencies. Seul le necessaire pour l’execution est present.

Ne jamais copier de secrets dans l’image

# INTERDIT : secrets en dur dans le Dockerfile
ENV DB_PASSWORD="monMotDePasse123"
COPY .env /app/.env

# CORRECT : passer les secrets via l'environnement ou Docker secrets
# docker-compose.yml :
# environment:
#   - DB_PASSWORD_FILE=/run/secrets/db_password
🔴

Critique

Un secret dans un Dockerfile reste dans l’image, meme si vous le supprimez dans un layer ulterieur. Les layers Docker sont immuables. Utilisez --secret de BuildKit ou les Docker secrets pour injecter les donnees sensibles au runtime.

Ajouter un HEALTHCHECK

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD curl -f http://localhost:8000/health || exit 1

Docker Compose : configuration securisee

Au-dela du Dockerfile, la configuration de l’orchestration joue un role cle dans la docker security. Voici un template docker-compose.yml securise :

services:
  app:
    image: mon-app:1.0.0
    user: "1000:1000"
    read_only: true
    tmpfs:
      - /tmp:noexec,nosuid,size=100m
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    security_opt:
      - no-new-privileges:true
      - seccomp:seccomp-profile.json
    ports:
      - "127.0.0.1:8000:8000"
    environment:
      - NODE_ENV=production
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: "1.0"
        reservations:
          memory: 128M

Explication des options :

Scanner les vulnerabilites avec Trivy

Trivy est un scanner de vulnerabilites open source developpe par Aqua Security. Il analyse les images Docker, les filesystems, les repositories Git et les configurations Kubernetes (IaC). C’est l’outil de reference pour le docker security scan.

Installer Trivy

# Debian/Ubuntu
sudo apt-get install wget apt-transport-https gnupg lsb-release
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo gpg --dearmor -o /usr/share/keyrings/trivy.gpg
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/trivy.list
sudo apt-get update && sudo apt-get install trivy

# Ou via le script d'installation rapide
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin

Scanner une image Docker

# Scan basique
trivy image mon-app:latest

# Scan avec sortie en format table
trivy image --format table mon-app:latest

# Scan avec seuil de severite (bloquer si CRITICAL ou HIGH)
trivy image --exit-code 1 --severity CRITICAL,HIGH mon-app:latest

# Scan en format JSON pour l'integration CI/CD
trivy image --format json --output trivy-report.json mon-app:latest

# Scanner une image depuis un registry prive
trivy image registry.linux-man.fr/mon-app:1.0.0
💡

A savoir

Trivy utilise la base de donnees NVD (National Vulnerability Database) mise a jour quotidiennement. Pour les environnements hors-ligne, vous pouvez telecharger la DB et l’utiliser localement.

Exemple de resultat Trivy

mon-app:latest (debian 12.5)

Total: 42 (UNKNOWN: 0, LOW: 12, MEDIUM: 18, HIGH: 10, CRITICAL: 2)

┌──────────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────────────┐
│   Library    │ Vulnerability │ Severity │ Status │ Installed Version │  Fixed Version        │
├──────────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────────────┤
│ openssl      │ CVE-2024-XXXX │ CRITICAL │ fixed  │ 3.0.11-1          │ 3.0.13-1             │
│ libcurl4     │ CVE-2024-XXXX │ HIGH     │ fixed  │ 7.88.1-10         │ 7.88.1-10+deb12u5    │
└──────────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────────────┘

Scanner le Dockerfile lui-meme (misconfiguration)

trivy config ./Dockerfile

Ce scan detecte les mauvaises pratiques comme l’utilisation de ADD au lieu de COPY, l’absence de HEALTHCHECK, ou l’utilisation de USER root.

Integrer le scan dans un pipeline CI/CD

Un scan manuel ne suffit pas. Le docker hardening doit etre automatise dans votre pipeline. Voici un exemple d’integration avec GitLab CI :

# .gitlab-ci.yml
stages:
  - build
  - scan
  - deploy

build:image:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

scan:trivy:
  stage: scan
  image: aquasec/trivy:latest
  script:
    - trivy image --exit-code 1 --severity CRITICAL,HIGH $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  allow_failure: false

deploy:production:
  stage: deploy
  image: docker:24
  services:
    - docker:24-dind
  script:
    - docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:production
    - docker push $CI_REGISTRY_IMAGE:production
  only:
    - main

Pour une approche plus complete de la publication d’images dans un registry prive, consultez notre guide sur la publication d’images Docker dans un registry GitLab avec CI/CD.

Astuce

Configurez Trivy pour bloquer le deploiement si des vulnerabilites CRITICAL sont detectees. Utilisez --exit-code 1 --severity CRITICAL pour echouer le job de scan.

Recapitulatif des bonnes pratiques

Categorie Action Priorite
Image de base Utiliser une image officielle, pinee et legere (-slim ou -alpine) Critique
Utilisateur Creer un user non-root et utiliser USER dans le Dockerfile Critique
Secrets Jamais de secrets en dur, utiliser BuildKit –secret ou Docker secrets Critique
Multi-stage Separer le build et le runtime pour reduire la taille de l’image Haute
Capabilities cap_drop: ALL + cap_add du strict necessaire Haute
Filesystem read_only: true avec tmpfs pour les repertoires d’ecriture Haute
Scan Trivy en CI/CD avec seuil CRITICAL/HIGH Haute
Reseaux Binder sur 127.0.0.1, reverse proxy devant Moyenne
Ressources Limiter CPU et memoire avec deploy.resources Moyenne
HEALTHCHECK Ajouter un HEALTHCHECK au Dockerfile Moyenne

FAQ

Est-il obligatoire d’utiliser un utilisateur non-root dans Docker ?
Ce n’est pas obligatoire mais fortement recommande. Executer en root dans un conteneur augmente le risque d’escalade de privileges si une vulnerabilite est exploitee. La plupart des applications n’ont pas besoin des privileges root pour fonctionner.
Trivy est-il gratuit pour un usage en production ?
Oui, Trivy est open source (licence Apache 2.0) et entierement gratuit, y compris en production. Aqua Security propose une version entreprise payante avec des fonctionnalites avancees (gestion des politiques, dashboard, etc.), mais la version communautaire couvre tous les besoins de base.
Quelle difference entre une image slim et alpine ?
Une image slim est une version reduite de l’image complete (meme distribution Linux, packages minimaux). Une image alpine utilise Alpine Linux, une distribution tres legere (environ 5 Mo). Attention : Alpine utilise musl libc au lieu de glibc, ce qui peut causer des problemes de compatibilite avec certaines dependances Python ou Node.js.
Comment scanner une image Docker sans la telecharger ?
Trivy peut scanner une image directement depuis un registry : trivy image registry.example.com/image:tag. Il ne telecharge que les metadonnees et les couches necessaires a l’analyse, pas l’image complete.
Les conteneurs non-root sont-ils vraiment plus securises ?
Oui, ils reduisent significativement l’impact d’une compromission. Un attaquant qui obtient un shell dans un conteneur non-root ne peut pas modifier les fichiers systeme, utiliser des ports privilegies (<1024) ou escalader vers le noyau via des capabilities. Combines avec no-new-privileges et cap_drop: ALL, les conteneurs non-root offrent une defense solide.

{
« @context »: « https://schema.org »,
« @type »: « FAQPage »,
« mainEntity »: [
{
« @type »: « Question »,
« name »: « Est-il obligatoire d’utiliser un utilisateur non-root dans Docker ? »,
« acceptedAnswer »: {
« @type »: « Answer »,
« text »: « Ce n’est pas obligatoire mais fortement recommande. Executer en root dans un conteneur augmente le risque d’escalade de privileges si une vulnerabilite est exploitee. »
}
},
{
« @type »: « Question »,
« name »: « Trivy est-il gratuit pour un usage en production ? »,
« acceptedAnswer »: {
« @type »: « Answer »,
« text »: « Oui, Trivy est open source (licence Apache 2.0) et entierement gratuit, y compris en production. »
}
},
{
« @type »: « Question »,
« name »: « Quelle difference entre une image slim et alpine ? »,
« acceptedAnswer »: {
« @type »: « Answer »,
« text »: « Une image slim est une version reduite de l’image complete (meme distribution Linux, packages minimaux). Une image alpine utilise Alpine Linux, une distribution tres legere (environ 5 Mo). »
}
},
{
« @type »: « Question »,
« name »: « Comment scanner une image Docker sans la telecharger ? »,
« acceptedAnswer »: {
« @type »: « Answer »,
« text »: « Trivy peut scanner une image directement depuis un registry avec la commande trivy image registry.example.com/image:tag. »
}
},
{
« @type »: « Question »,
« name »: « Les conteneurs non-root sont-ils vraiment plus securises ? »,
« acceptedAnswer »: {
« @type »: « Answer »,
« text »: « Oui, ils reduisent significativement l’impact d’une compromission. Un attaquant dans un conteneur non-root ne peut pas modifier les fichiers systeme ni utiliser des ports privilegies. »
}
}
]
}

Besoin d’un audit securite de vos conteneurs Docker ?

Nos experts DevOps analysent vos images, identifient les vulnerabilites et mettent en place un pipeline CI/CD securise.

Nous contacter →

Quitter la version mobile