LabHub
배우기 러닝패스 코스

KCSA — 쿠버네티스 보안 어소시에이트 · 플랫폼 보안 · 실습

어제와 같은 nginx:latest 가 오늘도 같은 이미지일까

LabHub 에서 이어서 보기

목표

같은 애플리케이션을 가리키는 세 가지 이미지 표기(다이제스트 고정 / latest 태그 / 사내 레지스트리 버전 태그)를
나란히 배포해 비교하고, imagePullPolicy·pull secret 을 출처에 맞게 설정한 뒤, ValidatingAdmissionPolicy 로
"허용 레지스트리이거나 다이제스트로 고정된 이미지만" 들이는 규칙을 집행하고 거절을 관찰합니다.

왜 중요한가

클라우드 네이티브 보안의 4C(Cloud·Cluster·Container·Code) 중 안쪽 두 층은 무엇을 돌리는가 의 문제입니다.
클러스터를 아무리 잘 잠가도, 파드가 끌어오는 이미지가 누군가 바꿔치기한 것이라면 방어는 안에서 무너집니다.

태그는 이름표일 뿐이라 레지스트리에서 언제든 다른 이미지로 다시 붙일 수 있습니다. nginx:latest 는 오늘과 내일이
다른 이미지일 수 있고, app:1.2.3 같은 버전 태그도 덮어쓰기를 막아 두지 않았다면 마찬가지입니다. 반면
@sha256:... 다이제스트는 이미지 내용의 해시라 한 글자만 달라져도 다른 값이 됩니다. 그래서 공급망 보안의 첫걸음은
"어떤 이미지가 태그로만 가리켜지고 있는가" 를 가려내는 것입니다.

imagePullPolicy 는 노드가 캐시를 믿을지 정합니다. 태그 이미지에 IfNotPresent 를 쓰면 노드마다 서로 다른 시점의
이미지를 돌리게 될 수 있습니다. 사내 레지스트리의 자격 증명은 pull secret 으로 주고, 서비스어카운트에 달아 두면
파드마다 반복하지 않아도 됩니다.

마지막으로 어드미션 정책은 생성 요청 시점에만 평가됩니다. 2단계에서 정책 없이 만든 Deployment 들은 6단계
정책이 켜진 뒤에도 그대로 남아 있습니다. 하지만 mutable(nginx:latest)의 파드가 지워져 ReplicaSet 이 새 파드를
만들려 하면 그 생성 요청은 거절됩니다 — 정책을 켜기 전에 기존 워크로드를 먼저 점검해야 하는 이유입니다.

단계

1. 네임스페이스 kcsa-supply 를 만듭니다.
2. pinned(다이제스트)·mutable(nginx:latestinternal(registry.example.com/app:1.2.3) Deployment 를 만듭니다.
3. 각 이미지를 digest/tag 로 분류해 /root/kcsa-supply/classify.txt 에 적습니다.
4. 태그 이미지는 imagePullPolicy: Always, 다이제스트 이미지는 IfNotPresent 로 바꿉니다.
5. docker-registry 시크릿 regcred 를 만들고 서비스어카운트 deployer 의 imagePullSecrets 에 답니다.
6. 허용 레지스트리 또는 다이제스트 고정만 통과시키는 정책 require-allowed-image 와 바인딩을 만듭니다.
7. docker.io/library/evil:1 파드가 거절되는 메시지를 /root/kcsa-supply/denied-image.txt 에 저장합니다.
8. 점검 결과를 /root/kcsa-supply/report.txt 에 남깁니다.

참고

단계 8개

  1. 출처를 따질 작업 구역 만들기
  2. 같은 nginx 인데 출처 표기가 셋 다 다르다
  3. 어느 이미지가 내일 바뀔 수 있는지 가려내기
  4. 태그를 믿지 말고 매번 다시 확인하게 하기
  5. 사내 레지스트리 자격 증명을 서비스어카운트에 달기
  6. 허용 레지스트리 밖의 이미지는 들이지 않는다
  7. Docker Hub 에서 온 낯선 이미지가 문 앞에서 막히다
  8. 이미지 출처 점검 결과를 장부로 남기기