Supprimer les secrets de build d'une image

DockerBeginner
Pratiquer maintenant

Introduction

Les secrets de build peuvent fuiter dans les images lorsque le Dockerfile copie une trop grande partie du contexte de build. L'erreur courante est COPY . /app/ : c'est pratique, mais cela peut inclure des jetons (tokens), des identifiants, des notes locales et des fichiers temporaires dans l'image finale. Une fois qu'un secret se trouve dans une couche d'image, les contrôles à l'exécution ne peuvent pas effacer de manière fiable cette erreur de chaîne d'approvisionnement.

Dans ce laboratoire, vous allez construire une image locale délibérément vulnérable, prouver qu'un jeton de build y est présent, puis corriger le build en restreignant la limite de copie du Dockerfile et en ajoutant un fichier .dockerignore. Enfin, vous déploierez l'image propre et vérifierez que le conteneur en cours d'exécution ne contient plus le secret de build.

Inspecter le contexte de build non sécurisé

Dans cette étape, vous allez inspecter le contexte de build et le Dockerfile non sécurisé. Le contexte de build est le répertoire envoyé au constructeur d'image. Si le Dockerfile copie l'intégralité du contexte, chaque fichier de ce répertoire peut faire partie de l'image finale.

Commencez dans l'espace de travail du laboratoire :

cd /home/labex/project/build-secret-image

Lisez les notes :

sed -n '1,120p' BUILD_SECRET_NOTES.md

Listez les fichiers qui existent actuellement dans le contexte de build :

find . -maxdepth 1 -type f -printf '%f\n' | sort | tee evidence/initial-context-files.txt

Examinez le Dockerfile non sécurisé :

sed -n '1,120p' Dockerfile.insecure | tee evidence/insecure-dockerfile-review.txt

La ligne risquée est COPY . /app/. Elle copie app.sh, mais elle copie également build-token.txt. À l'étape suivante, vous construirez cette image et prouverez la fuite depuis l'intérieur de l'exécution de l'image.

Construire l'image vulnérable et prouver la présence du secret

Dans cette étape, vous allez construire l'image non sécurisée à l'intérieur du profil minikube labex-v134. Construire à l'intérieur du profil rend l'image visible par le runtime du nœud Kubernetes.

Copiez le Dockerfile non sécurisé vers le nom de fichier Dockerfile actif et construisez l'image vulnérable :

cp Dockerfile.insecure Dockerfile
minikube -p labex-v134 image build -t labex/leaky-build:1.0 .

Exécutez l'image dans le runtime Docker de minikube et vérifiez la présence du fichier de jeton :

minikube -p labex-v134 ssh -- 'docker run --rm --entrypoint /bin/sh labex/leaky-build:1.0 -c "ls -l /app && cat /app/build-token.txt"' | tee evidence/leaky-image-contents.txt

Vous devriez voir build-token=labex-temporary-secret. C'est la fuite. L'image s'exécute, mais elle contient un fichier qui aurait dû rester en dehors de l'image finale.

Construire une image propre avec une limite de copie restreinte

Dans cette étape, vous allez corriger le build de l'image. Deux changements sont importants : .dockerignore empêche le jeton d'être inclus dans le contexte de build envoyé au constructeur, et le Dockerfile ne copie que app.sh au lieu de copier tout le répertoire.

Créez .dockerignore :

cat > .dockerignore <<'EOF'
build-token.txt
evidence/
*.txt
EOF

Créez le Dockerfile propre :

cat > Dockerfile <<'EOF'
FROM busybox:1.36

WORKDIR /app
COPY app.sh /app/app.sh
RUN chmod 0555 /app/app.sh

USER 65534:65534
ENTRYPOINT ["/app/app.sh"]
EOF

Construisez l'image propre :

minikube -p labex-v134 image build -t labex/clean-build:1.0 .

Inspectez l'image propre depuis l'intérieur du runtime Docker de minikube :

minikube -p labex-v134 ssh -- 'docker run --rm --entrypoint /bin/sh labex/clean-build:1.0 -c "ls -l /app; if [ -f /app/build-token.txt ]; then echo BUILD_SECRET_PRESENT; else echo NO_BUILD_SECRET; fi; id -u"' | tee evidence/clean-image-contents.txt

La sortie devrait afficher NO_BUILD_SECRET et l'UID 65534.

Déployer l'image propre

Dans cette étape, vous allez déployer l'image propre et vérifier que le conteneur en cours d'exécution indique qu'aucun secret de build n'est présent. Cela permet de garder la preuve finale proche de Kubernetes, là où l'image sera réellement exécutée.

Créez et appliquez le manifeste du Pod :

cat > clean-build-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: clean-build-app
  namespace: cks-prep-build-secret
  labels:
    app: clean-build-app
spec:
  restartPolicy: Never
  containers:
    - name: app
      image: labex/clean-build:1.0
      imagePullPolicy: Never
      securityContext:
        runAsNonRoot: true
        runAsUser: 65534
        runAsGroup: 65534
        allowPrivilegeEscalation: false
EOF
kubectl apply -f clean-build-pod.yaml

Attendez que le Pod soit prêt et lisez ses journaux :

kubectl -n cks-prep-build-secret wait --for=condition=Ready pod/clean-build-app --timeout=120s
kubectl -n cks-prep-build-secret logs clean-build-app | tee evidence/clean-pod-logs.txt

Les journaux devraient inclure :

clean build image ready
NO_BUILD_SECRET

Résumé

Vous avez inspecté un contexte de build d'image non sécurisé, construit une image vulnérable, prouvé que le jeton de build était présent, puis corrigé le build avec .dockerignore et une instruction COPY restreinte dans le Dockerfile. Vous avez construit et déployé une image propre qui s'exécute en tant qu'utilisateur non privilégié et indique NO_BUILD_SECRET. Cela termine l'étape de la chaîne d'approvisionnement en reliant l'hygiène de construction des images à la vérification à l'exécution dans Kubernetes.