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-managerDNS 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-managerPublic 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 따라 유료

시나리오별 추천

Yes

No

Yes

No

Yes

No

인증서 필요

Wildcard

필요?

DNS-01

80 포트

열 수 있나?

HTTP-01

DNS 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 ProfileAPI Tokens
  2. Create TokenEdit 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 알림 설정

참고 자료

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