Eliminar secretos de compilación de una imagen

DockerBeginner
Practicar Ahora

Introducción

Los secretos de compilación pueden filtrarse a las imágenes cuando un Dockerfile copia demasiado contexto de compilación. El error común es COPY . /app/: es conveniente, pero puede incluir tokens, credenciales, notas locales y archivos temporales en la imagen final. Una vez que un secreto está dentro de una capa de imagen, los controles en tiempo de ejecución no pueden eliminar de manera fiable este error en la cadena de suministro.

En este laboratorio, creará una imagen local deliberadamente vulnerable, demostrará que un token de compilación está presente en ella, luego corregirá la compilación limitando el alcance de la instrucción COPY en el Dockerfile y añadiendo un archivo .dockerignore. Finalmente, desplegará la imagen limpia y verificará que el contenedor en tiempo de ejecución ya no contenga el secreto de compilación.

Inspeccionar el contexto de compilación inseguro

En este paso, inspeccionará el contexto de compilación y el Dockerfile inseguro. El contexto de compilación es el directorio enviado al constructor de imágenes. Si el Dockerfile copia todo el contexto, cada archivo en ese directorio puede convertirse en parte de la imagen final.

Comience en el espacio de trabajo del laboratorio:

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

Lea las notas:

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

Enumere los archivos que existen actualmente en el contexto de compilación:

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

Revise el Dockerfile inseguro:

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

La línea de riesgo es COPY . /app/. Copia app.sh, pero también copia build-token.txt. En el siguiente paso, creará esta imagen y demostrará la fuga desde dentro del tiempo de ejecución de la imagen.

Crear la imagen con fugas y demostrar que el secreto está presente

En este paso, creará la imagen insegura dentro del perfil de minikube labex-v134. Construir dentro del perfil hace que la imagen sea visible para el tiempo de ejecución del nodo de Kubernetes.

Copie el Dockerfile inseguro al nombre de Dockerfile activo y cree la imagen con fugas:

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

Ejecute la imagen dentro del tiempo de ejecución de Docker de minikube y busque el archivo del token:

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

Debería ver build-token=labex-temporary-secret. Esa es la fuga. La imagen se ejecuta, pero contiene un archivo que debería haber permanecido fuera de la imagen final en tiempo de ejecución.

Crear una imagen limpia con un límite de copia restringido

En este paso, corregirá la compilación de la imagen. Dos cambios son importantes: .dockerignore mantiene el token fuera del contexto de compilación enviado al constructor, y el Dockerfile copia solo app.sh en lugar de copiar todo el directorio.

Cree .dockerignore:

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

Cree el Dockerfile limpio:

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

Cree la imagen limpia:

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

Inspeccione la imagen limpia desde dentro del tiempo de ejecución de 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 salida debería mostrar NO_BUILD_SECRET y el UID 65534.

Desplegar la imagen limpia

En este paso, desplegará la imagen limpia y verificará que el contenedor en ejecución informe que no hay ningún secreto de compilación presente. Esto mantiene la prueba final cerca de Kubernetes, donde la imagen se ejecutará realmente.

Cree y aplique el manifiesto del 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

Espere a que el Pod esté listo y lea sus registros:

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

Los registros deberían incluir:

clean build image ready
NO_BUILD_SECRET

Resumen

Inspeccionó un contexto de compilación de imagen inseguro, creó una imagen con fugas, demostró que el token de compilación estaba presente y luego corrigió la compilación con .dockerignore y una instrucción COPY de Dockerfile más específica. Creó y desplegó una imagen limpia que se ejecuta como un usuario no root e informa NO_BUILD_SECRET. Esto completa la etapa de la cadena de suministro al conectar la higiene en la compilación de imágenes con la verificación en tiempo de ejecución de Kubernetes.