본문으로 바로가기
728x90
반응형
SMALL

[K8s] 쿠버네티스 사설 레지스트리 구축 및 x509: certificate signed by unknown authority 에러 해결 가이드

쿠버네티스(Kubernetes) 환경에서 보안상의 이유로 사설 레지스트리(Private Registry)를 운영하다 보면 반드시 마주치는 문제가 있습니다. 바로 HTTPS/TLS 인증서 관련 에러입니다.

특히 ctr 명령어로는 이미지가 잘 당겨지는데, 정작 kubectl로 배포하면 ImagePullBackOff와 함께 "x509: certificate signed by unknown authority" 에러가 발생하는 상황에서의 완벽한 해결법을 정리합니다.

 

🟢 사설 TLS 인증서 생성 (OpenSSL)

사설 레지스트리를 HTTPS로 운영하기 위해서는 자체 서명 인증서(Self-Signed Certificate)가 필요합니다. 이때 주의할 점은 IP 주소를 인증서에 명시(SAN 설정)해야 한다는 것입니다.

인증서 생성 명령어

마스터 노드에서 아래 명령어를 실행하여 10년(3650일) 유효한 인증서를 생성합니다.

Bash

openssl req -newkey rsa:4096 -nodes -sha256 -keyout domain.key \
-x509 -days 3650 -out domain.crt \
-subj "/CN=10.202.2.129" \
-addext "subjectAltName = IP:10.202.2.129"

💡 왜 subjectAltName이 중요한가요?

최근의 컨테이너 런타임(containerd, Docker 등)은 보안상의 이유로 일반적인 Common Name(CN)만으로는 인증을 통과시키지 않습니다. subjectAltName (SAN) 필드에 레지스트리의 IP 주소가 정확히 명시되어야만 x509: certificate signed by unknown authority 에러를 방지할 수 있습니다.


 

🟢 쿠버네티스 Secret 등록

생성된 domain.crtdomain.key를 쿠버네티스 클러스터에서 사용할 수 있도록 Secret 객체로 등록합니다.

Bash

# 기존 시크릿이 있다면 삭제 후 재생성
kubectl delete secret registry-tls --ignore-not-found

# TLS 타입의 시크릿 생성
kubectl create secret tls registry-tls \
  --cert=domain.crt \
  --key=domain.key



1. 사설 레지스트리(Private Registry) 배포 설정

사설 레지스트리는 내부망에서 이미지를 안전하게 관리하기 위해 필수적입니다. 아래는 TLS 인증서를 적용한 registry.yaml 예시입니다.

Registry Deployment & Service YAML

YAML

apiVersion: apps/v1
kind: Deployment
metadata:
  name: private-registry
spec:
  replicas: 1
  selector:
    matchLabels:
      app: registry
  template:
    metadata:
      labels:
        app: registry
    spec:
      dnsPolicy: ClusterFirstWithHostNet
      containers:
      - name: registry
        image: registry:2
        env:
        - name: REGISTRY_HTTP_ADDR
          value: "0.0.0.0:30500"
        - name: REGISTRY_HTTP_TLS_CERTIFICATE
          value: /certs/tls.crt
        - name: REGISTRY_HTTP_TLS_KEY
          value: /certs/tls.key
        ports:
        - containerPort: 5000
        volumeMounts:
        - name: storage
          mountPath: /var/lib/registry
        - name: cert-vol
          mountPath: /certs
          readOnly: true
      volumes:
      - name: storage
        persistentVolumeClaim:
          claimName: watercluster-pvc
      - name: cert-vol
        secret:
          secretName: registry-tls
---
apiVersion: v1
kind: Service
metadata:
  name: registry-service
spec:
  type: NodePort
  selector:
    app: registry
  ports:
    - port: 30500
      targetPort: 30500
      nodePort: 30500

2. 트러블슈팅: x509 인증서 에러 해결 (CentOS/RHEL)

사설 인증서(Self-Signed Certificate)를 사용하면 쿠버네티스 노드들은 해당 레지스트리를 신뢰하지 않습니다. 이를 해결하기 위해 모든 마스터 및 워커 노드에서 다음 작업을 수행해야 합니다.

단계 1: 시스템 인증서 저장소에 등록

레지스트리 서버에서 인증서를 추출하여 OS 신뢰 목록에 추가합니다.

Bash

# 1. 인증서 추출 (129번은 레지스트리 IP)
openssl s_client -showcerts -connect 10.202.2.129:30500 </dev/null 2>/dev/null | openssl x509 -outform PEM > /tmp/registry.crt

# 2. 신뢰 저장소 경로로 복사
sudo cp /tmp/registry.crt /etc/pki/ca-trust/source/anchors/watercluster-registry.crt

# 3. 인증서 갱신
sudo update-ca-trust extract

 

단계 2: containerd 설정 최적화 (핵심 포인트)

많은 분이 /etc/containerd/config.tomlconfig_path를 설정하지만, 사설 인증서를 OS에 등록했다면 이 설정이 오히려 충돌을 일으킬 수 있습니다.

Bash

sudo vi /etc/containerd/config.toml

수정 내용: 아래 설정을 찾아 주석 처리합니다.

Ini, TOML

[plugins."io.containerd.grpc.v1.cri".registry]
  # config_path = "/etc/containerd/certs.d"  <-- 주석 처리

이렇게 하면 containerd가 개별 설정 대신 시스템 기본 인증서 저장소를 참조하게 되어 훨씬 안정적입니다.

 

단계 3: 서비스 완전 재시작

설정 적용을 위해 엔진을 새로고침합니다.

Bash

sudo systemctl daemon-reload
sudo systemctl restart containerd
sudo systemctl restart kubelet

 

3. 대규모 환경에서의 자동화 (Ansible)

관리해야 할 서버가 100대 이상이라면 수동 작업은 불가능합니다. Ansible을 활용하면 폐쇄망 환경에서도 안전하고 빠르게 인증서를 배포할 수 있습니다.

  • 에이전트 미설치(Agentless): SSH만 연결되면 즉시 실행 가능.
  • 멱등성 보장: 여러 번 실행해도 동일한 설정 상태 유지.
  • 폐쇄망 최적화: 외부 인터넷 없이도 내부망 내에서 모든 노드 제어 가능.

 

4. 서비스 노출 시 포트 매핑 이해

외부 접속을 위해 Serviceports 설정을 할 때 다음의 구분을 명확히 해야 접속 오류를 방지할 수 있습니다.

포트 항목 설명 예시
port 클러스터 내부 서비스 IP에서 사용하는 포트 8080
targetPort 컨테이너 내부 앱(Tomcat 등)이 실제 리스닝하는 포트 8080
nodePort 외부에서 노드 IP를 통해 접속할 때 사용하는 포트 30080

요약 및 결론

  1. 사설 레지스트리 사용 시 인증서 에러는 필수 관문입니다.
  2. OS 레벨(update-ca-trust)에 인증서를 등록하는 것이 가장 확실한 방법입니다.
  3. containerdconfig_path 설정 충돌을 주의해야 합니다.
  4. 서버 대수가 많다면 Ansible과 같은 자동화 도구 도입을 적극 고려하세요.

도움이 되셨다면 공감과 댓글 부탁드립니다! 추가적인 질문은 언제든 환영합니다.

728x90
반응형
LIST