Security - Secret of Docker Registry

2026. 1. 2. 17:26·CKA

이번 글에서는 Kubernetes에서 “이미지 보안”을 다룰 때 가장 먼저 알아야 하는 두 가지를 정리합니다.

  1. 이미지 이름이 실제로 무엇을 의미하는지(어디서 가져오는지)
  2. Private Registry 이미지를 Pod가 안전하게 Pull하도록 설정하는 방법

1) image: nginx는 정확히 어디서 뭘 가져오는 걸까?

Pod 스펙에서 흔히 이렇게 씁니다.

containers:
- name: web
  image: nginx

겉보기엔 단순하지만, nginx는 Docker 이미지 명명 규칙에 의해 “풀 네임”으로 해석됩니다.

이미지 이름의 정식 형태

일반적으로 컨테이너 이미지는 아래 구조로 이해하면 됩니다.

[registryhost[:port]/][namespace/]repository[:tag][@digest]

예를 들어:

  • nginx
  • library/nginx:1.27
  • docker.io/library/nginx:1.27
  • ghcr.io/my-org/my-app:1.0.3
  • registry.mycorp.com/platform/api@sha256:...

nginx가 풀 네임으로 바뀌는 규칙

image: nginx처럼 registry/namespace를 생략하면 대부분의 런타임이 다음처럼 간주합니다.

  • registry: docker.io (Docker Hub)
  • namespace: library (공식 이미지가 모이는 기본 네임스페이스/계정)
  • tag: latest (tag를 생략했을 때 기본값)

즉,

nginx  ≈  docker.io/library/nginx:latest

library는 Docker Hub의 “공식 이미지(Official Images)”가 위치한 기본 네임스페이스로 이해하면 됩니다.


2) Registry(레지스트리)란?

레지스트리는 “이미지를 저장/배포하는 저장소 서버”입니다.

  • 이미지를 빌드/업데이트하면 레지스트리에 push
  • 다른 시스템(노드)이 배포하려면 레지스트리에서 pull

대표적으로:

  • Docker Hub: docker.io
  • GitHub Container Registry: ghcr.io
  • Google 계열: gcr.io / Artifact Registry(*.pkg.dev)
  • 클라우드 프라이빗 레지스트리: AWS ECR, Azure ACR 등
  • 사내 레지스트리: Harbor, Nexus 등

공개 이미지(누구나 pull 가능)도 있고, 비공개 이미지(인증 필요)도 있습니다.


3) Private Registry 이미지를 Kubernetes에서 쓰려면?

로컬 PC에서는 보통 이렇게 합니다.

docker login registry.mycorp.com
docker pull registry.mycorp.com/team/app:1.0.0

하지만 Kubernetes에서는 “Pod가 뜨는 워커 노드에서” 이미지 pull이 발생합니다.
즉, 노드의 런타임(containerd/docker)이 레지스트리 인증정보를 알아야 합니다.

Kubernetes는 이 문제를 Secret + imagePullSecrets로 해결합니다.


4) 방법 1: Docker Registry 타입 Secret 만들기 (가장 흔함)

4.1 Secret 생성 (명령형)

kubectl create secret docker-registry regcred \
  --docker-server=registry.mycorp.com \
  --docker-username=myuser \
  --docker-password='mypassword' \
  --docker-email=myuser@mycorp.com \
  -n default
  • docker-registry 타입 Secret은 내부적으로 레지스트리 인증정보를 저장하는 전용 형태입니다.
  • 결과 Secret은 보통 kubernetes.io/dockerconfigjson 타입으로 만들어집니다.

확인:

kubectl get secret regcred -n default
kubectl describe secret regcred -n default

실무 팁: 비밀번호를 CLI 인자로 직접 넣으면 쉘 히스토리에 남을 수 있습니다. 가능하면 안전한 입력 방식(환경변수/CI secret/파일)을 사용하세요.


5) Pod에 imagePullSecrets 지정하기

Pod 스펙에 imagePullSecrets를 추가합니다.

apiVersion: v1
kind: Pod
metadata:
  name: private-nginx
  namespace: default
spec:
  containers:
  - name: nginx
    image: registry.mycorp.com/library/nginx:1.27
  imagePullSecrets:
  - name: regcred

이제 Pod가 생성되면, kubelet이 API 서버에서 regcred를 받아 런타임에 전달하고, 런타임이 해당 자격증명으로 이미지를 pull합니다.


6) 방법 2: ServiceAccount에 imagePullSecrets를 붙여 “기본 적용”하기

Pod마다 imagePullSecrets를 반복해서 넣기 싫다면, ServiceAccount에 연결할 수 있습니다.

6.1 ServiceAccount에 regcred 연결

kubectl patch serviceaccount default \
  -p '{"imagePullSecrets":[{"name":"regcred"}]}' \
  -n default

이렇게 하면 default SA를 사용하는 Pod들은 별도 설정 없이도 해당 Secret을 사용해 이미지를 pull할 수 있습니다.

또는 전용 SA를 만들어서 특정 워크로드에만 적용하는 게 더 안전합니다.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-sa
  namespace: default
imagePullSecrets:
- name: regcred

그리고 Deployment(또는 Pod)에:

spec:
  template:
    spec:
      serviceAccountName: app-sa

7) 트러블슈팅: ImagePullBackOff / ErrImagePull가 뜰 때

가장 먼저 Pod 이벤트를 보세요.

kubectl describe pod <pod-name> -n <ns>

자주 나오는 원인:

  • 레지스트리 주소 오타 (registry.mycorp.com vs registry.mycorp.co)
  • 이미지 경로/태그 오타 (repo:tag)
  • Secret이 다른 네임스페이스에 있음
    • Secret은 네임스페이스 리소스라 Pod와 같은 네임스페이스에 있어야 합니다.
  • 권한 부족(해당 계정이 repo pull 권한 없음)
  • TLS/인증서 이슈(사내 레지스트리 자체 서명 인증서 등)

8) “이미지 보안” 관점에서 꼭 같이 챙길 베스트 프랙티스

이 강의는 “인증을 통해 private image pull”에 초점이지만, 실무에서 이미지 보안은 여기까지 같이 묶어 생각하는 경우가 많습니다.

8.1 latest 태그 지양

latest는 내용이 바뀔 수 있어 재현성이 떨어집니다.

  • 권장: 명시적 버전 태그(:1.0.3) 또는 digest pinning(@sha256:...)

8.2 최소 권한 원칙

  • 레지스트리 계정은 pull 전용으로
  • Secret은 필요한 네임스페이스/SA에만

8.3 스캔/서명/정책

  • 이미지 취약점 스캔(레지스트리 스캔/CI 스캔)
  • 이미지 서명(cosign 등) + Admission 정책(OPA/Gatekeeper, Kyverno)로 “서명된 이미지만 허용”
  • 허용된 레지스트리만 사용하도록 정책화

요약

  • image: nginx는 보통 docker.io/library/nginx:latest로 해석된다.
  • Private Registry 이미지를 쓰려면 “노드가 pull할 때 쓸 인증정보”가 필요하다.
  • Kubernetes는 이를 Secret(docker-registry) + imagePullSecrets로 해결한다.
  • 반복을 줄이려면 ServiceAccount에 imagePullSecrets를 붙이는 방식이 유용하다.
  • 실무에서는 latest 지양, 최소권한, 스캔/서명/정책까지 같이 묶어서 이미지 보안을 완성한다.

 

Practice Test: https://uklabs.kodekloud.com/topic/practice-test-image-security-2/

'CKA' 카테고리의 다른 글

Security - NetworkPolicy  (0) 2026.01.02
Security - 도커 보안 기초 + 쿠버네티스의 Security Context  (0) 2026.01.02
Security - Service Account  (0) 2026.01.02
Security - ClusterRole / ClusterRoleBinding  (0) 2026.01.02
Security - Authorization(RBAC)  (0) 2026.01.01
'CKA' 카테고리의 다른 글
  • Security - NetworkPolicy
  • Security - 도커 보안 기초 + 쿠버네티스의 Security Context
  • Security - Service Account
  • Security - ClusterRole / ClusterRoleBinding
5jyan5
5jyan5
  • 5jyan5
    jyan
    5jyan5
  • 전체
    오늘
    어제
    • 분류 전체보기 (243)
      • 김영한의 스프링 핵심 원리(기본편) (8)
      • 김영한의 스프링 핵심 원리 - 고급편 (11)
      • 김영한의 스프링 MVC 1편 (1)
      • 김영한의 스프링 DB 1편 (3)
      • 김영한의 스프링 MVC 2편 (3)
      • 김영한의 ORM 표준 JPA 프로그래밍(기본편) (9)
      • 김영한의 스프링 부트와 JPA 활용2 (2)
      • 김영한의 실전 자바 - 중급 1편 (1)
      • 김영한의 실전 자바 - 고급 1편 (9)
      • 김영한의 실전 자바 - 고급 2편 (9)
      • Readable Code: 읽기 좋은 코드를 작성.. (2)
      • 김영한의 실전 자바 - 고급 3편 (9)
      • CKA (119)
      • 개발 (37)
      • 경제 (4)
      • 리뷰 (1)
      • 정보 (2)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      @discriminatorvalue
      log trace
      hibernate5module
      cglib
      단방향 맵핑
      Thread
      reentarantlock
      @discriminatorcolumn
      typequery
      자바
      jpq
      @within
      @args
      WAS
      JPQL
      gesingleresult
      requset scope
      양방향 맵핑
      빈 후처리기
      스레드
      고급
      조회 성능 최적화
      Target
      프록시
      jdk 동적 프록시
      프록시 팩토리
      페치 조인
      김영한
      락
      버퍼
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.2
    5jyan5
    Security - Secret of Docker Registry
    상단으로

    티스토리툴바