Introduction
La sécurité de la chaîne d'approvisionnement commence avant même qu'une charge de travail ne soit exécutée dans le cluster. Si une image contient des outils inutiles, une provenance incertaine ou une balise (tag) non approuvée, les contrôles d'exécution que vous avez étudiés précédemment présentent un risque accru. Une image minimale approuvée doit disposer d'un contexte de construction réduit, d'une image de base claire, d'un point d'entrée d'application explicite, d'étiquettes (labels) de métadonnées utiles et de preuves qu'elle peut s'exécuter dans le cluster cible.
Dans ce laboratoire, vous allez créer un contexte de construction d'image local réduit, construire l'image au sein du profil minikube labex-v134, inspecter les métadonnées de l'image résultante, la déployer avec imagePullPolicy: Never et vérifier le contenu à l'exécution depuis Kubernetes. Ce laboratoire reste pragmatique : vous ne scannez pas encore les images et vous n'appliquez pas encore de politique de registre. Vous apprenez ici le premier réflexe de la chaîne d'approvisionnement : construire une image petite, nommée et inspectable, et prouver ce qu'elle contient.
Créer un contexte de construction d'image réduit
Dans cette étape, vous allez créer les fichiers qui constitueront l'image. Un contexte de construction est le répertoire envoyé au constructeur d'image. Il est important de maintenir ce contexte aussi petit que possible, car chaque fichier supplémentaire est une opportunité d'inclure par erreur des éléments inutiles dans l'image.
Commencez dans l'espace de travail du laboratoire :
cd /home/labex/project/minimal-approved-image
Lisez les notes du laboratoire :
sed -n '1,160p' IMAGE_BUILD_NOTES.md
Confirmez le contexte CKS et l'espace de noms (namespace) :
kubectl config current-context | tee context-check.txt
kubectl get namespace cks-prep-image | tee namespace-check.txt
Créez le script de l'application. Ce script affiche un message de disponibilité, imprime l'UID d'exécution, puis se met en pause afin que Kubernetes puisse maintenir le conteneur actif pour inspection.
cat > app.sh <<'EOF'
#!/bin/sh
set -eu
echo "minimal approved image ready"
echo "runtime uid: $(id -u)"
sleep 300
EOF
chmod 0755 app.sh
Créez le Dockerfile. busybox:1.36 est l'image de base légère utilisée pour ce laboratoire. Les étiquettes de style OCI enregistrent la raison pour laquelle cette image est approuvée dans le cadre du laboratoire, et USER 65534:65534 permet à l'image de s'exécuter par défaut en tant qu'utilisateur numérique non privilégié.
cat > Dockerfile <<'EOF'
FROM busybox:1.36
LABEL org.opencontainers.image.title="minimal-approved-app"
LABEL org.opencontainers.image.source="local-cks-prep"
LABEL security.labex.io.approved="true"
WORKDIR /app
COPY app.sh /app/app.sh
RUN chmod 0555 /app/app.sh
USER 65534:65534
ENTRYPOINT ["/app/app.sh"]
EOF
Enregistrez l'inventaire du contexte de construction et une somme de contrôle (checksum) du script de l'application :
find . -maxdepth 1 -type f -printf '%f\n' | sort | tee build-context-files.txt
sha256sum app.sh | tee app-sha256.txt
sed -n '1,120p' Dockerfile | tee dockerfile-review.txt
Votre répertoire contient désormais le Dockerfile, app.sh, les notes et les fichiers de preuve que vous avez sauvegardés. La limite importante de l'image est définie par la ligne COPY dans le Dockerfile : seul app.sh est copié dans /app/app.sh à l'intérieur de l'image.
Construire l'image dans le profil Minikube
Dans cette étape, vous allez construire l'image dans le profil minikube labex-v134. Il est crucial de la construire à cet endroit car Kubernetes exécutera les conteneurs à partir du runtime du nœud minikube. Si vous construisez l'image uniquement sur le démon Docker de la machine virtuelle hôte, le nœud minikube pourrait ne pas être en mesure de la voir.
Construisez l'image avec une balise locale explicite :
minikube -p labex-v134 image build -t labex/minimal-approved:1.0 .
Inspectez l'image à l'intérieur du profil minikube. La première commande confirme que l'image existe dans le runtime du nœud. La seconde commande enregistre les métadonnées clés, notamment l'utilisateur configuré, le point d'entrée et les étiquettes.
minikube -p labex-v134 ssh -- 'docker image ls labex/minimal-approved:1.0' | tee built-image-list.txt
minikube -p labex-v134 ssh -- 'docker image inspect labex/minimal-approved:1.0' | tee built-image-inspect.json
Utilisez jq pour extraire les champs pertinents pour la preuve d'approbation :
jq '.[0].Config | {User, Entrypoint, Labels}' built-image-inspect.json | tee built-image-approval.json
Vous devriez voir la balise de l'image dans built-image-list.txt, l'utilisateur (User) défini sur 65534:65534, le point d'entrée (Entrypoint) sur /app/app.sh et l'étiquette d'approbation définie sur true.
Exécuter l'image approuvée dans Kubernetes
Dans cette étape, vous allez exécuter l'image locale dans Kubernetes. Le Pod utilise imagePullPolicy: Never car l'image a été construite à l'intérieur du profil minikube plutôt que poussée vers un registre. Ce paramètre indique à Kubernetes d'utiliser l'image du nœud local et d'échouer si elle n'est pas présente.
Créez le manifeste du Pod :
cat > approved-image-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: approved-image-app
namespace: cks-prep-image
labels:
app: approved-image-app
supply-chain.labex.io/approved: "true"
spec:
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 65534
runAsGroup: 65534
containers:
- name: app
image: labex/minimal-approved:1.0
imagePullPolicy: Never
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
EOF
Appliquez le Pod et attendez qu'il soit prêt :
kubectl apply -f approved-image-pod.yaml
kubectl wait --for=condition=Ready pod/approved-image-app -n cks-prep-image --timeout=120s
Enregistrez les journaux (logs) du Pod et le YAML actuel du Pod :
kubectl logs approved-image-app -n cks-prep-image | tee approved-image-logs.txt
kubectl get pod approved-image-app -n cks-prep-image -o yaml | tee approved-image-pod.current.yaml
Les journaux devraient afficher minimal approved image ready et runtime uid: 65534. Cela prouve que Kubernetes exécute bien le point d'entrée de l'image en tant qu'utilisateur non privilégié prévu.
Vérifier le contenu à l'exécution
Dans cette étape, vous allez inspecter le conteneur en cours d'exécution depuis Kubernetes. L'approbation d'une image ne doit pas se limiter à un nom de balise. Vous devez obtenir la preuve que l'environnement d'exécution contient le chemin d'application attendu et ne contient pas de fichiers supplémentaires évidents qui n'auraient jamais dû faire partie de l'image.
Inspectez le répertoire de l'application :
kubectl exec -n cks-prep-image approved-image-app -- sh -c 'ls -la /app; test -f /app/app.sh; echo APP_PATH_OK' | tee runtime-app-path.txt
Vérifiez l'utilisateur d'exécution et effectuez une petite vérification négative pour détecter tout fichier de débogage inutile :
kubectl exec -n cks-prep-image approved-image-app -- sh -c 'id -u; test ! -e /app/debug-tool && echo NO_DEBUG_TOOL' | tee runtime-content-check.txt
Enregistrez un enregistrement d'approbation final et compact qui combine l'état de Kubernetes avec les métadonnées de l'image :
kubectl get pod approved-image-app -n cks-prep-image -o json | jq '{image: .spec.containers[0].image, imagePullPolicy: .spec.containers[0].imagePullPolicy, podSecurityContext: .spec.securityContext, containerSecurityContext: .spec.containers[0].securityContext}' | tee final-pod-approval.json
jq '.[0].Config | {User, Entrypoint, Labels}' built-image-inspect.json | tee final-image-approval.json
La preuve finale devrait montrer la balise de l'image locale approuvée, imagePullPolicy: Never, les paramètres d'exécution non privilégiés, le point d'entrée /app/app.sh et l'étiquette d'approbation.
Résumé
Vous avez pratiqué le premier flux de travail de la chaîne d'approvisionnement dans ce cours de préparation au CKS : construire et prouver une image minimale approuvée. Vous avez créé un contexte de construction réduit, construit labex/minimal-approved:1.0 dans le profil minikube labex-v134, inspecté les métadonnées et les étiquettes de l'image, déployé l'image locale avec imagePullPolicy: Never, et vérifié l'utilisateur d'exécution ainsi que le contenu de l'application depuis Kubernetes. Les prochains laboratoires sur la chaîne d'approvisionnement s'appuieront sur ces bases avec l'analyse des manifestes, la révision des sorties Helm, les preuves SBOM et de somme de contrôle, les contrôles de registre de confiance et le nettoyage des secrets de construction.



