Введение
Секреты сборки могут попасть в образы, если Dockerfile копирует слишком много файлов из контекста сборки. Распространенная ошибка — использование COPY . /app/: это удобно, но может привести к попаданию токенов, учетных данных, локальных заметок и временных файлов в итоговый образ. Как только секрет оказывается внутри слоя образа, средства защиты времени выполнения уже не могут надежно исправить эту ошибку в цепочке поставок.
В этой лабораторной работе вы создадите намеренно уязвимый локальный образ, докажете наличие в нем токена сборки, а затем исправите процесс сборки, сузив область копирования в Dockerfile и добавив .dockerignore. В завершение вы развернете чистый образ и убедитесь, что контейнер во время выполнения больше не содержит секрет сборки.
Изучение небезопасного контекста сборки
На этом этапе вы изучите контекст сборки и небезопасный Dockerfile. Контекст сборки — это директория, которая отправляется сборщику образа. Если Dockerfile копирует весь контекст, каждый файл в этой директории может стать частью итогового образа.
Начните работу в рабочей директории лаборатории:
cd /home/labex/project/build-secret-image
Прочитайте заметки:
sed -n '1,120p' BUILD_SECRET_NOTES.md
Выведите список файлов, которые в данный момент существуют в контексте сборки:
find . -maxdepth 1 -type f -printf '%f\n' | sort | tee evidence/initial-context-files.txt
Изучите небезопасный Dockerfile:
sed -n '1,120p' Dockerfile.insecure | tee evidence/insecure-dockerfile-review.txt
Рискованная строка — COPY . /app/. Она копирует app.sh, но также копирует build-token.txt. На следующем этапе вы соберете этот образ и докажете наличие утечки изнутри запущенного контейнера.
Сборка уязвимого образа и доказательство наличия секрета
На этом этапе вы соберете небезопасный образ внутри профиля minikube labex-v134. Сборка внутри профиля делает образ видимым для среды выполнения Kubernetes.
Скопируйте небезопасный Dockerfile в основной файл Dockerfile и соберите уязвимый образ:
cp Dockerfile.insecure Dockerfile
minikube -p labex-v134 image build -t labex/leaky-build:1.0 .
Запустите образ внутри среды выполнения Docker в minikube и проверьте наличие файла с токеном:
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
Вы должны увидеть build-token=labex-temporary-secret. Это и есть утечка. Образ работает, но содержит файл, который должен был остаться за пределами итогового образа.
Сборка чистого образа с ограниченной областью копирования
На этом этапе вы исправите сборку образа. Важны два изменения: .dockerignore предотвращает попадание токена в контекст сборки, а Dockerfile копирует только app.sh вместо всей директории.
Создайте .dockerignore:
cat > .dockerignore <<'EOF'
build-token.txt
evidence/
*.txt
EOF
Создайте чистый Dockerfile:
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
Соберите чистый образ:
minikube -p labex-v134 image build -t labex/clean-build:1.0 .
Проверьте чистый образ изнутри среды выполнения Docker в 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
Вывод должен показать NO_BUILD_SECRET и UID 65534.
Развертывание чистого образа
На этом этапе вы развернете чистый образ и убедитесь, что запущенный контейнер подтверждает отсутствие секрета сборки. Это приближает проверку к реальным условиям Kubernetes, где образ будет использоваться.
Создайте и примените манифест пода:
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
Дождитесь готовности пода и прочитайте его логи:
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
Логи должны содержать:
clean build image ready
NO_BUILD_SECRET
Резюме
Вы изучили небезопасный контекст сборки образа, создали уязвимый образ, доказали наличие в нем токена сборки, а затем исправили сборку с помощью .dockerignore и точной инструкции COPY в Dockerfile. Вы собрали и развернули чистый образ, который работает от имени пользователя без прав root и сообщает NO_BUILD_SECRET. Это завершает этап обеспечения безопасности цепочки поставок, связывая гигиену сборки образов с проверкой во время выполнения в Kubernetes.



