Введение
Безопасность цепочки поставок начинается еще до того, как рабочая нагрузка будет запущена в кластере. Если образ содержит ненужные инструменты, имеет неясное происхождение или несанкционированный тег, риски, связанные с элементами управления средой выполнения, о которых вы узнали ранее, возрастают. Минимальный одобренный образ должен иметь небольшой контекст сборки, четко определенный базовый образ, явную точку входа приложения, полезные метаданные в виде меток и подтверждение того, что он может работать в целевом кластере.
В этой лабораторной работе вы создадите небольшой локальный контекст сборки образа, соберете образ внутри профиля minikube labex-v134, изучите метаданные полученного образа, развернете его с параметром imagePullPolicy: Never и проверите содержимое среды выполнения средствами Kubernetes. Эта работа носит практический характер: вы пока не занимаетесь сканированием образов и не внедряете политики реестра. Вы осваиваете базовый навык обеспечения безопасности цепочки поставок: создание небольшого, именованного, проверяемого образа и подтверждение того, что находится внутри него.
Создание контекста сборки небольшого образа
На этом этапе вы создадите файлы, которые станут основой образа. Контекст сборки — это директория, отправляемая сборщику образов. Важно поддерживать минимальный размер контекста сборки, так как каждый лишний файл — это потенциальная возможность случайно скопировать что-то ненужное в образ.
Начните работу в рабочей директории:
cd /home/labex/project/minimal-approved-image
Ознакомьтесь с заметками к лабораторной работе:
sed -n '1,160p' IMAGE_BUILD_NOTES.md
Подтвердите контекст CKS и пространство имен:
kubectl config current-context | tee context-check.txt
kubectl get namespace cks-prep-image | tee namespace-check.txt
Создайте скрипт приложения. Этот скрипт выводит сообщение о готовности, печатает UID среды выполнения, а затем переходит в режим ожидания, чтобы Kubernetes мог поддерживать контейнер запущенным для проверки.
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
Создайте Dockerfile. busybox:1.36 — это небольшой базовый образ для данной лабораторной работы. Метки в стиле OCI фиксируют причину одобрения этого образа в рамках лабораторной работы, а USER 65534:65534 заставляет образ по умолчанию запускаться от имени непривилегированного числового пользователя.
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
Сохраните инвентаризацию контекста сборки и контрольную сумму скрипта приложения:
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
Теперь в вашей директории будут находиться Dockerfile, app.sh, заметки и файлы с доказательствами. Важной границей образа является строка COPY в Dockerfile: только app.sh копируется в /app/app.sh внутри образа.
Сборка образа внутри профиля Minikube
На этом этапе вы соберете образ в профиле minikube labex-v134. Сборка именно там важна, потому что Kubernetes будет запускать контейнеры из среды выполнения узла minikube. Если вы соберете образ только во внешнем Docker-демоне виртуальной машины, узел minikube может его не увидеть.
Соберите образ с понятным локальным тегом:
minikube -p labex-v134 image build -t labex/minimal-approved:1.0 .
Изучите образ внутри профиля minikube. Первая команда подтверждает наличие образа в среде выполнения узла. Вторая команда сохраняет ключевые метаданные, включая настроенного пользователя, точку входа и метки.
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
Используйте jq для извлечения полей, важных для подтверждения одобрения:
jq '.[0].Config | {User, Entrypoint, Labels}' built-image-inspect.json | tee built-image-approval.json
Вы должны увидеть тег образа в built-image-list.txt, User, установленный в 65534:65534, Entrypoint, установленный в /app/app.sh, и метку одобрения, установленную в true.
Запуск одобренного образа в Kubernetes
На этом этапе вы запустите локальный образ в Kubernetes. В Pod используется imagePullPolicy: Never, так как образ был собран внутри профиля minikube, а не отправлен в реестр. Эта настройка указывает Kubernetes использовать локальный образ узла и выдать ошибку, если он отсутствует.
Создайте манифест 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
Примените манифест Pod и дождитесь его запуска:
kubectl apply -f approved-image-pod.yaml
kubectl wait --for=condition=Ready pod/approved-image-app -n cks-prep-image --timeout=120s
Сохраните логи Pod и текущий YAML-файл 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
В логах должно быть видно minimal approved image ready и runtime uid: 65534. Это доказывает, что Kubernetes запускает точку входа образа от имени нужного непривилегированного пользователя.
Проверка содержимого среды выполнения
На этом этапе вы изучите запущенный контейнер средствами Kubernetes. Одобрение образа не должно ограничиваться только тегом. Вам нужны доказательства того, что среда выполнения содержит ожидаемый путь к приложению и не содержит очевидных лишних файлов, которые не должны были быть частью образа.
Изучите директорию приложения:
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
Проверьте пользователя среды выполнения и выполните небольшую негативную проверку на наличие ненужного отладочного файла:
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
Сохраните компактную итоговую запись об одобрении, объединяющую состояние Kubernetes с метаданными образа:
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
Итоговые доказательства должны содержать тег локального одобренного образа, imagePullPolicy: Never, настройки среды выполнения от имени непривилегированного пользователя, точку входа /app/app.sh и метку одобрения.
Резюме
Вы отработали первый рабочий процесс цепочки поставок в рамках этого курса подготовки к CKS: создание и подтверждение минимального одобренного образа. Вы создали небольшой контекст сборки, собрали labex/minimal-approved:1.0 внутри профиля minikube labex-v134, изучили метаданные и метки образа, развернули локальный образ с imagePullPolicy: Never и проверили пользователя среды выполнения и содержимое приложения средствами Kubernetes. В последующих лабораторных работах по цепочке поставок этот фундамент будет дополнен сканированием манифестов, проверкой вывода Helm, доказательствами SBOM и контрольными суммами, элементами управления доверенными реестрами и очисткой секретов сборки.



