K8s cert-manager TLS 자동화

K8s cert-manager란?

cert-manager는 Kubernetes에서 TLS 인증서를 자동으로 발급·갱신·관리하는 컨트롤러다. Let’s Encrypt 같은 ACME CA부터 사내 CA, Vault까지 다양한 발급자를 지원한다. 수동 인증서 관리의 실수와 만료 사고를 근본적으로 방지한다.

1. cert-manager 설치

# Helm으로 설치
helm repo add jetstack https://charts.jetstack.io
helm repo update

helm install cert-manager jetstack/cert-manager 
  --namespace cert-manager 
  --create-namespace 
  --set crds.enabled=true 
  --set prometheus.enabled=true

# 설치 확인
kubectl get pods -n cert-manager
# cert-manager, cert-manager-cainjector, cert-manager-webhook 3개 Pod

2. Issuer와 ClusterIssuer

인증서 발급자를 정의하는 두 리소스의 차이:

리소스 범위 사용 시나리오
Issuer 네임스페이스 내 팀별 다른 CA 사용 시
ClusterIssuer 클러스터 전체 공통 Let’s Encrypt 사용 시
# Let's Encrypt Staging (테스트용)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-staging-key
    solvers:
      - http01:
          ingress:
            ingressClassName: nginx

---
# Let's Encrypt Production
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod-key
    solvers:
      - http01:
          ingress:
            ingressClassName: nginx

⚠️ 반드시 staging으로 먼저 테스트한 후 production으로 전환하자. Let’s Encrypt production은 Rate Limit이 있어 잦은 재시도 시 차단될 수 있다.

3. Certificate 리소스로 발급

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: api-tls
  namespace: default
spec:
  secretName: api-tls-secret    # 인증서가 저장될 Secret
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  commonName: api.example.com
  dnsNames:
    - api.example.com
    - www.api.example.com
  duration: 2160h        # 90일
  renewBefore: 360h      # 만료 15일 전 갱신
  privateKey:
    algorithm: ECDSA
    size: 256
# 인증서 상태 확인
kubectl get certificate
kubectl describe certificate api-tls

# 발급된 Secret 확인
kubectl get secret api-tls-secret -o yaml
# tls.crt, tls.key, ca.crt 포함

4. Ingress 자동 TLS (Annotation)

가장 간편한 방법은 Ingress에 annotation을 추가하는 것이다. cert-manager가 자동으로 Certificate를 생성하고 갱신한다.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    # 선택: 인증서 옵션
    cert-manager.io/private-key-algorithm: "ECDSA"
    cert-manager.io/private-key-size: "256"
    cert-manager.io/duration: "2160h"
    cert-manager.io/renew-before: "360h"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - api.example.com
        - admin.example.com
      secretName: api-tls-auto    # cert-manager가 자동 생성
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 8080
    - host: admin.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: admin-service
                port:
                  number: 3000

Ingress 설정 심화는 K8s Ingress NGINX 심화 글을 참고하자.

5. DNS01 챌린지: 와일드카드 인증서

HTTP01은 와일드카드(*.example.com)를 지원하지 않는다. DNS01 solver가 필요하다.

# Cloudflare DNS01 Solver
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-dns
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-dns-key
    solvers:
      - dns01:
          cloudflare:
            email: admin@example.com
            apiTokenSecretRef:
              name: cloudflare-api-token
              key: api-token

---
# Cloudflare API Token Secret
apiVersion: v1
kind: Secret
metadata:
  name: cloudflare-api-token
  namespace: cert-manager
type: Opaque
stringData:
  api-token: "your-cloudflare-api-token"

---
# 와일드카드 인증서
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-tls
spec:
  secretName: wildcard-tls-secret
  issuerRef:
    name: letsencrypt-dns
    kind: ClusterIssuer
  dnsNames:
    - "example.com"
    - "*.example.com"
챌린지 와일드카드 요구사항
HTTP01 포트 80 오픈, Ingress 필요
DNS01 DNS 프로바이더 API 접근

6. 사내 CA와 자체 서명 인증서

# 자체 서명 CA
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}

---
# CA 인증서 생성
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: internal-ca
  namespace: cert-manager
spec:
  isCA: true
  commonName: internal-ca
  secretName: internal-ca-secret
  duration: 87600h    # 10년
  issuerRef:
    name: selfsigned-issuer
    kind: ClusterIssuer

---
# CA 기반 Issuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: internal-ca-issuer
spec:
  ca:
    secretName: internal-ca-secret

내부 서비스 간 mTLS에 자체 CA를 사용하면 Let’s Encrypt Rate Limit 걱정 없이 인증서를 발급할 수 있다. K8s Secret 관리 전반은 K8s 시크릿 암호화 3가지 글을 참고하자.

7. 모니터링과 트러블슈팅

# 인증서 상태 전체 확인
kubectl get certificates --all-namespaces
kubectl get certificaterequests --all-namespaces
kubectl get orders --all-namespaces
kubectl get challenges --all-namespaces

# 이벤트 확인
kubectl describe certificate api-tls
# Events:
#   Normal  Issuing    cert-manager  Issuing certificate...
#   Normal  Generated  cert-manager  Stored new private key
#   Normal  Requested  cert-manager  Created new CertificateRequest
#   Normal  Issuing    cert-manager  The certificate has been successfully issued

# Prometheus 메트릭
# certmanager_certificate_ready_status
# certmanager_certificate_expiration_timestamp_seconds

# 갱신 실패 알림 (PrometheusRule)
- alert: CertificateExpiringSoon
  expr: certmanager_certificate_expiration_timestamp_seconds - time() < 7 * 24 * 3600
  for: 1h
  labels:
    severity: warning
  annotations:
    summary: "인증서 {{ $labels.name }} 7일 내 만료"

마무리

cert-manager는 K8s 환경에서 TLS 인증서 관리를 완전히 자동화한다. Ingress annotation 한 줄로 Let's Encrypt 인증서를 발급받고, DNS01로 와일드카드를 처리하며, 자체 CA로 내부 mTLS를 구축할 수 있다. 핵심은 staging에서 테스트 → production 전환만료 모니터링 알림 설정이다.

위로 스크롤
WordPress Appliance - Powered by TurnKey Linux