ACME Challenge 완벽 가이드: HTTP-01 vs DNS-01 (Let's Encrypt, ZeroSSL 등)

2025년 12월 09일

devops

# ACME# Let's Encrypt# ZeroSSL# SSL# TLS# cert-manager# Kubernetes
목차

ACME란?

ACME (Automatic Certificate Management Environment)는 표준 인증서 자동 발급 프로토콜입니다. 2019년 IETF에서 RFC 8555로 표준화되었습니다.

ACME를 지원하는 CA (Certificate Authority)

ACME는 Let’s Encrypt만의 프로토콜이 아닙니다. 여러 CA들이 지원합니다:

CA 무료 상용 특징
Let’s Encrypt ✅ ❌ 가장 유명, 90일 갱신
ZeroSSL ✅ ✅ 90일 무료, 유료 플랜 제공
Buypass Go SSL ✅ ❌ 180일 갱신 (노르웨이)
Google Trust Services ✅ ❌ 90일, Google Cloud 통합
Sectigo (상용) ❌ ✅ 기업용, OV/EV 인증서
DigiCert (상용) ❌ ✅ 기업용, 고급 검증

cert-manager에서 다른 CA 사용 예시:

# ZeroSSL 사용
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: zerossl
spec:
  acme:
    server: https://acme.zerossl.com/v2/DV90
    email: admin@example.com
    externalAccountBinding:
      keyID: your-eab-kid
      keySecretRef:
        name: zerossl-eab
        key: secret
    privateKeySecretRef:
      name: zerossl-key
    solvers:
      - http01:
          ingress:
            class: nginx
---
# Buypass 사용 (180일 인증서)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: buypass
spec:
  acme:
    server: https://api.buypass.com/acme/directory
    email: admin@example.com
    privateKeySecretRef:
      name: buypass-key
    solvers:
      - http01:
          ingress:
            class: nginx

왜 Let’s Encrypt가 가장 유명한가?

  1. 완전 무료: 상업적 제한 없음
  2. 자동화: ACME 프로토콜 최초 구현 및 대중화
  3. 커뮤니티 지원: cert-manager 등 도구들의 기본 설정
  4. 신뢰성: Mozilla, Chrome, EFF 등의 후원

다른 CA를 고려해야 할 때:

  • Buypass: 180일 인증서 필요 시 (Let’s Encrypt는 90일)
  • ZeroSSL: 상용 지원 필요 시
  • Google Trust Services: GCP 환경에서 통합 필요 시
  • DigiCert/Sectigo: OV/EV 인증서 필요 시 (회사 정보 검증)

참고: 대부분의 경우 Let’s Encrypt로 충분하며, 이 글의 예시도 주로 Let’s Encrypt를 사용합니다.

ACME Challenge란?

인증서를 발급받기 위해서는 도메인 소유권을 증명해야 하는데, 이 검증 과정을 Challenge라고 합니다.

Challenge 종류

Challenge 타입 검증 방식 포트 요구사항 Wildcard 지원
HTTP-01 HTTP 응답 검증 80 필수 ❌
DNS-01 DNS TXT 레코드 검증 불필요 ✅
TLS-ALPN-01 TLS 핸드셰이크 검증 443 필수 ❌

HTTP-01 Challenge

동작 원리

DNS ServerHTTP ServerLet's Encryptcert-manager1. 인증서 요청 (example.com)2. Challenge Token 발급3. Token을 HTTP 서버에 배치/.well-known/acme-challenge/<token>4. example.com의 IP 조회5. IP 주소 반환6. http://example.com/.well-known/acme-challenge/<token> 접근7. Token 값 반환8. 검증 성공, 인증서 발급

검증 과정 상세

  1. 인증서 요청: cert-manager가 Let’s Encrypt에 인증서 발급 요청
  2. Challenge 생성: Let’s Encrypt가 랜덤 토큰 생성 (예: abc123xyz)
  3. HTTP 엔드포인트 노출: cert-manager가 임시 Pod를 생성하여 다음 경로에 토큰 배치
    http://example.com/.well-known/acme-challenge/abc123xyz
  4. 검증: Let’s Encrypt가 해당 URL에 접근하여 토큰 확인
  5. 인증서 발급: 검증 성공 시 인증서 발급

Kubernetes에서 HTTP-01 Challenge

1. ClusterIssuer 설정

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-http01
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-http01-key
    solvers:
      - http01:
          ingress:
            class: nginx  # 또는 traefik

2. Certificate 생성

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-cert
  namespace: default
spec:
  secretName: example-tls
  issuerRef:
    name: letsencrypt-http01
    kind: ClusterIssuer
  dnsNames:
    - example.com
    - www.example.com

3. Challenge Pod 확인

# Challenge 리소스 확인
kubectl get challenges

# Challenge Pod 확인
kubectl get pods -l acme.cert-manager.io/http01-solver=true

# Challenge Ingress 확인
kubectl get ingress -A | grep cm-acme-http-solver

자동 생성되는 리소스:

# cert-manager가 자동으로 생성하는 임시 Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: cm-acme-http-solver-xxxxx
spec:
  rules:
    - host: example.com
      http:
        paths:
          - path: /.well-known/acme-challenge/abc123xyz
            pathType: Exact
            backend:
              service:
                name: cm-acme-http-solver-xxxxx
                port:
                  number: 8089

HTTP-01 장점

✅ 간단한 설정: DNS 설정 불필요, Ingress만 있으면 됨 ✅ 빠른 검증: 즉시 검증 가능 (DNS 전파 대기 불필요) ✅ 무료 DNS API 불필요: 외부 서비스 연동 불필요 ✅ 대부분의 호스팅 지원: 일반적인 웹 서버 환경에서 작동

HTTP-01 단점

❌ 80 포트 필수: 방화벽에서 80 포트 개방 필요 ❌ Wildcard 인증서 불가: *.example.com 발급 불가 ❌ 내부 네트워크 불가: 인터넷에서 접근 가능한 도메인만 가능 ❌ 멀티 인증서 충돌: 같은 도메인에 여러 Challenge 동시 실행 시 충돌 가능

HTTP-01 사용 사례

적합한 경우:

  • 일반 웹 애플리케이션 (example.com, www.example.com)
  • 80 포트가 열려 있는 환경
  • 단일 도메인 또는 서브도메인별 인증서
  • 빠른 발급이 필요한 경우

예시:

# 블로그, E-Commerce, SaaS 애플리케이션
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: webapp-cert
spec:
  secretName: webapp-tls
  issuerRef:
    name: letsencrypt-http01
    kind: ClusterIssuer
  dnsNames:
    - blog.example.com
    - shop.example.com
    - app.example.com

DNS-01 Challenge

동작 원리

Public DNSDNS ProviderLet's Encryptcert-manager1. 인증서 요청 (*.example.com)2. Challenge Token 발급3. TXT 레코드 생성_acme-challenge.example.com = "token"4. DNS 레코드 전파 (60초~10분)5. _acme-challenge.example.com TXT 조회6. DNS 쿼리7. TXT 레코드 반환8. Token 값 반환9. 검증 성공, 인증서 발급10. TXT 레코드 삭제 (정리)

검증 과정 상세

  1. 인증서 요청: cert-manager가 Wildcard 인증서 요청 (*.example.com)
  2. Challenge 생성: Let’s Encrypt가 랜덤 토큰 생성
  3. TXT 레코드 추가: cert-manager가 DNS Provider API를 통해 다음 레코드 생성
    _acme-challenge.example.com. IN TXT "abc123xyz"
  4. DNS 전파 대기: 전 세계 DNS 서버에 레코드 전파 (60초~10분)
  5. 검증: Let’s Encrypt가 Public DNS로 TXT 레코드 조회
  6. 인증서 발급: 검증 성공 시 인증서 발급
  7. 레코드 정리: cert-manager가 TXT 레코드 삭제

Kubernetes에서 DNS-01 Challenge

1. Cloudflare를 사용한 ClusterIssuer

apiVersion: v1
kind: Secret
metadata:
  name: cloudflare-api-token
  namespace: cert-manager
stringData:
  api-token: "your-cloudflare-api-token"
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-dns01-cloudflare
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-dns01-key
    solvers:
      - dns01:
          cloudflare:
            email: admin@example.com
            apiTokenSecretRef:
              name: cloudflare-api-token
              key: api-token

2. Route53을 사용한 ClusterIssuer

apiVersion: v1
kind: Secret
metadata:
  name: route53-credentials
  namespace: cert-manager
stringData:
  secret-access-key: "AWS_SECRET_ACCESS_KEY"
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-dns01-route53
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-dns01-key
    solvers:
      - dns01:
          route53:
            region: us-east-1
            accessKeyID: AKIAIOSFODNN7EXAMPLE
            secretAccessKeySecretRef:
              name: route53-credentials
              key: secret-access-key

3. Google Cloud DNS를 사용한 ClusterIssuer

apiVersion: v1
kind: Secret
metadata:
  name: clouddns-service-account
  namespace: cert-manager
stringData:
  key.json: |
    {
      "type": "service_account",
      "project_id": "my-project",
      "private_key_id": "...",
      "private_key": "...",
      "client_email": "cert-manager@my-project.iam.gserviceaccount.com"
    }
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-dns01-clouddns
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-dns01-key
    solvers:
      - dns01:
          cloudDNS:
            project: my-project
            serviceAccountSecretRef:
              name: clouddns-service-account
              key: key.json

4. Wildcard 인증서 발급

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-cert
  namespace: default
spec:
  secretName: wildcard-tls
  issuerRef:
    name: letsencrypt-dns01-cloudflare
    kind: ClusterIssuer
  dnsNames:
    - "*.example.com"
    - example.com  # Apex 도메인도 포함

지원되는 DNS Provider

cert-manager가 지원하는 주요 DNS Provider:

Provider 설정 난이도 API 비용 전파 속도
Cloudflare 쉬움 무료 빠름 (1-2분)
Route53 보통 유료 ($0.50/zone) 빠름 (1-2분)
Google Cloud DNS 보통 유료 ($0.20/zone) 빠름 (1-2분)
Azure DNS 보통 유료 중간 (3-5분)
DigitalOcean 쉬움 무료 중간 (3-5분)
RFC2136 어려움 무료 (BIND 등) 빠름

DNS-01 장점

✅ Wildcard 인증서: *.example.com 발급 가능 ✅ 포트 불필요: 80, 443 포트 개방 불필요 ✅ 내부 네트워크 가능: 인터넷 접근 불필요 (DNS만 공개) ✅ 멀티 서브도메인 효율적: 하나의 인증서로 모든 서브도메인 커버 ✅ 방화벽 우회: 엄격한 방화벽 환경에서도 작동

DNS-01 단점

❌ DNS Provider API 필요: API 토큰/자격증명 관리 필요 ❌ DNS 전파 시간: 검증에 수 분 소요 (HTTP-01보다 느림) ❌ 복잡한 설정: DNS Provider별 설정 방법 다름 ❌ 보안 위험: DNS API 토큰 유출 시 도메인 탈취 위험 ❌ 비용 발생 가능: 일부 Provider는 유료 (Route53, Cloud DNS 등)

DNS-01 사용 사례

적합한 경우:

  • Wildcard 인증서가 필요한 경우
  • 80 포트를 열 수 없는 환경 (기업 방화벽)
  • 내부 네트워크 환경
  • 멀티 테넌트 SaaS (테넌트별 서브도메인)
  • API Gateway, CDN 등 다수의 서브도메인

예시 1: 멀티 테넌트 SaaS

# tenant1.saas.com, tenant2.saas.com, ... 모두 커버
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: saas-wildcard
spec:
  secretName: saas-wildcard-tls
  issuerRef:
    name: letsencrypt-dns01-cloudflare
    kind: ClusterIssuer
  dnsNames:
    - "*.saas.com"
    - saas.com

예시 2: 내부 Kubernetes 클러스터

# 80 포트가 막혀있는 내부 네트워크
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: internal-cert
spec:
  secretName: internal-tls
  issuerRef:
    name: letsencrypt-dns01-route53
    kind: ClusterIssuer
  dnsNames:
    - "*.internal.company.com"

TLS-ALPN-01 Challenge (참고)

개요

TLS-ALPN-01은 TLS 핸드셰이크 과정에서 검증하는 방식입니다. HTTP-01의 대안으로 고안되었지만, 실무에서는 거의 사용되지 않습니다.

특징

  • 포트: 443 포트 사용
  • Wildcard: 지원 안 함
  • 장점: 80 포트 불필요
  • 단점: 대부분의 Ingress Controller가 미지원

왜 잘 안 쓰이나?

  • NGINX Ingress, Traefik 등에서 공식 지원 제한적
  • HTTP-01이 더 널리 지원되고 안정적
  • DNS-01이 Wildcard를 지원하므로 대체 가능

HTTP-01 vs DNS-01 비교

기능 비교

항목 HTTP-01 DNS-01
Wildcard ❌ ✅
80 포트 필요 ✅ ❌
DNS API 필요 ❌ ✅
검증 속도 빠름 (10초) 느림 (1-10분)
내부 네트워크 ❌ ✅
설정 복잡도 낮음 높음
보안 위험 낮음 중간 (API 토큰)
비용 무료 Provider 따라 유료

시나리오별 추천

YesNoYesNoYesNo인증서 필요Wildcard필요?DNS-0180 포트열 수 있나?HTTP-01DNS API사용 가능?호스팅 업체 확인

시나리오별 선택:

시나리오 추천 이유
블로그, 포트폴리오 HTTP-01 간단, 빠름
멀티 테넌트 SaaS DNS-01 Wildcard 필요
기업 내부 서비스 DNS-01 80 포트 제한
E-Commerce HTTP-01 안정적, 검증됨
API Gateway DNS-01 다수 서브도메인
Development HTTP-01 빠른 테스트

실무 가이드

HTTP-01 설정 예시 (NGINX Ingress)

# 1. ClusterIssuer
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:
            class: nginx
---
# 2. Ingress (자동 인증서 발급)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - example.com
      secretName: example-tls  # cert-manager가 자동 생성
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: myapp
                port:
                  number: 80

DNS-01 설정 예시 (Cloudflare)

# 1. Cloudflare API 토큰 Secret
apiVersion: v1
kind: Secret
metadata:
  name: cloudflare-api-token
  namespace: cert-manager
type: Opaque
stringData:
  api-token: "your-cloudflare-api-token"
---
# 2. ClusterIssuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-dns-cloudflare
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
        selector:
          dnsZones:
            - example.com
---
# 3. Wildcard Certificate
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-example
  namespace: default
spec:
  secretName: wildcard-example-tls
  issuerRef:
    name: letsencrypt-dns-cloudflare
    kind: ClusterIssuer
  dnsNames:
    - "*.example.com"
    - example.com

Cloudflare API 토큰 생성 방법

  1. Cloudflare 대시보드 → My Profile → API Tokens
  2. Create Token → Edit zone DNS 템플릿 사용
  3. Permissions:
    • Zone - DNS - Edit
    • Zone - Zone - Read
  4. Zone Resources:
    • Include - Specific zone - example.com
  5. 토큰 복사 후 Secret에 저장

AWS Route53 IAM 정책

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "route53:GetChange",
        "route53:ListHostedZones"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "route53:ChangeResourceRecordSets",
        "route53:ListResourceRecordSets"
      ],
      "Resource": "arn:aws:route53:::hostedzone/HOSTED_ZONE_ID"
    }
  ]
}

트러블슈팅

HTTP-01 Challenge 실패

문제 1: “Waiting for HTTP-01 challenge propagation”에서 멈춤

원인:

  • 80 포트가 열려있지 않음
  • Ingress Controller가 Challenge Ingress를 인식 못함
  • DNS가 잘못된 IP를 가리킴

해결:

# 1. Challenge 상태 확인
kubectl describe challenge <challenge-name>

# 2. Challenge Ingress 확인
kubectl get ingress -A | grep cm-acme-http-solver

# 3. Challenge Pod 로그 확인
kubectl logs -l acme.cert-manager.io/http01-solver=true

# 4. 외부에서 접근 테스트
curl -v http://example.com/.well-known/acme-challenge/test

# 5. DNS 확인
dig example.com
nslookup example.com

해결 방법:

# Ingress Class를 명시적으로 지정
spec:
  acme:
    solvers:
      - http01:
          ingress:
            class: nginx
            podTemplate:
              spec:
                nodeSelector:
                  kubernetes.io/os: linux

문제 2: “Connection refused” 또는 “Timeout”

원인:

  • 방화벽에서 80 포트 차단
  • Load Balancer가 Health Check 실패
  • Ingress Controller Pod가 없음

해결:

# LoadBalancer 확인
kubectl get svc -n ingress-nginx

# Ingress Controller Pod 확인
kubectl get pods -n ingress-nginx

# 80 포트 접근 테스트
telnet <external-ip> 80

DNS-01 Challenge 실패

문제 1: “DNS record not found” 또는 “DNS propagation timeout”

원인:

  • DNS API 인증 실패
  • TXT 레코드 생성 실패
  • DNS 전파가 느림

해결:

# 1. Challenge 상태 확인
kubectl describe challenge <challenge-name>

# 2. TXT 레코드 확인
dig _acme-challenge.example.com TXT
nslookup -type=TXT _acme-challenge.example.com

# 3. cert-manager 로그 확인
kubectl logs -n cert-manager -l app=cert-manager

# 4. DNS Provider 로그 확인 (Cloudflare 예시)
# Cloudflare 대시보드 → Audit Log

해결 방법:

# DNS 전파 대기 시간 늘리기
spec:
  acme:
    solvers:
      - dns01:
          cloudflare:
            email: admin@example.com
            apiTokenSecretRef:
              name: cloudflare-api-token
              key: api-token
        # DNS 전파 대기 (기본 60초)
        selector:
          dnsZones:
            - example.com

문제 2: “Invalid API token” 또는 “Permission denied”

원인:

  • API 토큰 만료
  • 권한 부족
  • Secret 오타

해결:

# Secret 확인
kubectl get secret cloudflare-api-token -n cert-manager -o yaml

# Secret 값 디코딩
kubectl get secret cloudflare-api-token -n cert-manager \
  -o jsonpath='{.data.api-token}' | base64 -d

# API 토큰 테스트 (Cloudflare)
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

문제 3: DNS Provider 별 이슈

Cloudflare:

# Zone ID 명시적 지정
dns01:
  cloudflare:
    apiTokenSecretRef:
      name: cloudflare-api-token
      key: api-token
    # Zone ID 추가 (선택사항)

Route53:

# 리전 명시
dns01:
  route53:
    region: us-east-1  # 명시적 리전 지정
    accessKeyID: AKIAIOSFODNN7EXAMPLE
    secretAccessKeySecretRef:
      name: route53-credentials
      key: secret-access-key

Google Cloud DNS:

# 프로젝트 ID 확인
dns01:
  cloudDNS:
    project: my-project-id  # 정확한 프로젝트 ID
    serviceAccountSecretRef:
      name: clouddns-service-account
      key: key.json

디버깅 커맨드 모음

# Certificate 상태 확인
kubectl get certificate
kubectl describe certificate <cert-name>

# CertificateRequest 확인
kubectl get certificaterequest
kubectl describe certificaterequest <request-name>

# Order 확인
kubectl get order
kubectl describe order <order-name>

# Challenge 확인 (상세)
kubectl get challenges
kubectl describe challenge <challenge-name>

# cert-manager 로그
kubectl logs -n cert-manager -l app=cert-manager -f

# Challenge Pod 로그 (HTTP-01)
kubectl logs -l acme.cert-manager.io/http01-solver=true

# Challenge Ingress 확인 (HTTP-01)
kubectl get ingress -A | grep cm-acme-http-solver
kubectl describe ingress <challenge-ingress>

# DNS 레코드 확인 (DNS-01)
dig _acme-challenge.example.com TXT +short
nslookup -type=TXT _acme-challenge.example.com 8.8.8.8

# Secret 확인
kubectl get secret <tls-secret> -o yaml
kubectl get secret <tls-secret> -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -noout

# 인증서 만료일 확인
kubectl get secret <tls-secret> -o jsonpath='{.data.tls\.crt}' | \
  base64 -d | openssl x509 -noout -dates

# Challenge 수동 삭제 (재시도)
kubectl delete challenge --all
kubectl delete order --all
kubectl delete certificaterequest --all

성능 및 모니터링

인증서 발급 시간 비교

Challenge 타입 평균 발급 시간 최대 시간
HTTP-01 10-30초 2분
DNS-01 2-5분 10분

모니터링 설정

Prometheus Rule (인증서 만료 알림):

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: cert-manager-alerts
spec:
  groups:
    - name: certificates
      rules:
        - alert: CertificateExpiringSoon
          expr: |
            certmanager_certificate_expiration_timestamp_seconds - time() < 604800
          for: 1h
          labels:
            severity: warning
          annotations:
            summary: "Certificate {{ $labels.name }} expiring in 7 days"
            description: "Certificate {{ $labels.name }} in namespace {{ $labels.namespace }} expires in less than 7 days"

        - alert: CertificateRenewalFailed
          expr: |
            certmanager_certificate_ready_status{condition="False"} == 1
          for: 1h
          labels:
            severity: critical
          annotations:
            summary: "Certificate {{ $labels.name }} renewal failed"
            description: "Certificate {{ $labels.name }} in namespace {{ $labels.namespace }} failed to renew"

Best Practices

보안

  1. API 토큰 관리

    • Secret은 cert-manager Namespace에만 저장
    • RBAC으로 접근 제한
    • 토큰 정기 교체 (6개월마다)
    • Sealed Secrets 또는 External Secrets 사용 권장
  2. 최소 권한 원칙

    # Cloudflare: Zone DNS Edit만 허용
    # Route53: 특정 Hosted Zone만 허용
    # GCP: 특정 프로젝트만 허용
  3. Production vs Staging

    # Staging (테스트용, Rate Limit 높음)
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    
    # Production (실제 인증서)
    server: https://acme-v02.api.letsencrypt.org/directory

효율성

  1. Wildcard 인증서 재사용

    # 하나의 Wildcard 인증서로 모든 Ingress 커버
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: wildcard-shared
    spec:
      secretName: wildcard-tls
      dnsNames:
        - "*.example.com"
    ---
    # 모든 Ingress에서 재사용
    spec:
      tls:
        - secretName: wildcard-tls
  2. DNS-01 Selector 활용

    # 특정 도메인만 DNS-01 사용
    solvers:
      - dns01:
          cloudflare:
            apiTokenSecretRef:
              name: cloudflare-api-token
              key: api-token
        selector:
          dnsZones:
            - "*.internal.example.com"
      - http01:
          ingress:
            class: nginx
        selector:
          dnsNames:
            - "www.example.com"
  3. 인증서 갱신 모니터링

    • cert-manager는 만료 30일 전 자동 갱신 시도
    • Prometheus + Alertmanager로 실패 감지
    • Slack/Email 알림 설정

참고 자료

© 2026, 미나리와 함께 만들었음