소개
Dockerfile 이 빌드 컨텍스트를 과도하게 복사하면 빌드 시크릿이 이미지 내부로 유출될 수 있습니다. COPY . /app/과 같은 방식은 편리하지만, 토큰, 자격 증명, 로컬 메모, 임시 파일 등을 최종 이미지에 포함시킬 위험이 있습니다. 일단 시크릿이 이미지 레이어에 포함되면, 런타임 제어만으로는 이러한 공급망 실수를 안정적으로 수정하기 어렵습니다.
이 실습에서는 의도적으로 보안에 취약한 로컬 이미지를 빌드하고, 스테이징 빌드 토큰이 이미지 내부에 존재하는지 확인합니다. 그 후, .dockerignore를 추가하고 Dockerfile 의 복사 범위를 좁혀 빌드 과정을 수정합니다. 마지막으로, 안전한 이미지를 배포하여 런타임 컨테이너에 더 이상 빌드 시크릿이 포함되지 않음을 검증합니다.
보안에 취약한 빌드 컨텍스트 검사
이 단계에서는 빌드 컨텍스트와 보안에 취약한 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까지 복사합니다. 다음 단계에서는 이 이미지를 빌드하고 이미지 런타임 내부에서 유출 사실을 증명하겠습니다.
취약한 이미지 빌드 및 시크릿 포함 여부 확인
이 단계에서는 labex-v134 minikube 프로필 내에서 취약한 이미지를 빌드합니다. 프로필 내부에서 빌드하면 Kubernetes 노드 런타임에서 이미지를 확인할 수 있습니다.
취약한 Dockerfile 을 활성 Dockerfile 이름으로 복사하고 이미지를 빌드합니다:
cp Dockerfile.insecure Dockerfile
minikube -p labex-v134 image build -t labex/leaky-build:1.0 .
minikube Docker 런타임 내에서 이미지를 실행하고 토큰 파일이 있는지 확인합니다:
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 .
minikube Docker 런타임 내부에서 안전한 이미지를 검사합니다:
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 환경에서 최종 검증을 수행하는 것입니다.
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
Pod 가 준비될 때까지 기다린 후 로그를 확인합니다:
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와 제한된 Dockerfile COPY 명령을 사용하여 빌드 과정을 수정했습니다. 비루트 (non-root) 사용자로 실행되며 NO_BUILD_SECRET을 보고하는 안전한 이미지를 빌드하고 배포했습니다. 이로써 이미지 빌드 위생을 Kubernetes 런타임 검증과 연결하여 공급망 보안 단계를 완료했습니다.



