콘텐츠로 이동

Add Jetstack Helm repository

플랫폼명령어
kubectl (Static Manifests)kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.yaml
Helm (Recommended)helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --set installCRDs=true
macOS (cmctl CLI)brew install cmctl
Linux (cmctl CLI)`curl -sSL https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cmctl-linux-amd64.tar.gz \
Windows (cmctl CLI)curl.exe -L -o cmctl.exe https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cmctl-windows-amd64.exe
Verify Installationkubectl get pods -n cert-manager
# Add Jetstack Helm repository
helm repo add jetstack https://charts.jetstack.io

# Update repository
helm repo update

# Install with custom values
helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version v1.13.3 \
  --values custom-values.yaml
```## 설치

| 명령어 | 설명 |
|---------|-------------|
| `kubectl get certificates` | 현재 네임스페이스의 모든 인증서 나열 |
| `kubectl get certificates -A` | 모든 네임스페이스에 걸쳐 인증서 나열 |
| `kubectl describe certificate <name>` | 자세한 인증서 정보 표시 |
| `kubectl get certificate <name> -o yaml` | YAML 형식으로 인증서 보기 |
| `kubectl get issuer` | 현재 네임스페이스의 모든 발급자 나열 |
| `kubectl get clusterissuer` | 클러스터 전체 발급자 나열 |
| `kubectl describe issuer <name>` | 발행자 상세 정보 표시 |
| `kubectl get certificaterequest` | 인증서 요청 목록 |
| `kubectl get order` | ACME 인증서 주문 보기 |
| `kubectl get challenge` | ACME 도메인 검증 챌린지 보기 |
| `kubectl logs -n cert-manager deployment/cert-manager` | cert-manager 컨트롤러 로그 보기 |
| `kubectl logs -n cert-manager deployment/cert-manager-webhook` | 웹훅 로그 보기 |
| `kubectl logs -n cert-manager deployment/cert-manager-cainjector` | CA 인젝터 로그 보기 |
| `cmctl check api` | cert-manager API를 사용 가능한지 확인하세요 |
| `cmctl version` | cert-manager 버전 정보 표시 |
| `cmctl status certificate <name>` | 인증서 상태 및 준비 상태 확인 |
| `cmctl inspect secret <secret-name>` | cert-manager에 의해 생성된 TLS 시크릿 검사 |
| `cmctl renew <cert-name>` | 인증서 갱신을 수동으로 트리거 |
| `kubectl get crd \ | grep cert-manager` | cert-manager 사용자 정의 리소스 정의(Custom Resource Definitions) 나열하기 |
| `kubectl get events --field-selector involvedObject.name=<cert-name>` | 특정 인증서와 관련된 이벤트 보기 |### Helm 저장소 설정

| 명령어 | 설명 |
|---------|-------------|
| `cmctl approve <certificaterequest-name>` | 인증서 요청을 수동으로 승인하기 |
| `cmctl deny <certificaterequest-name>` | 인증서 요청 거부 |
| `cmctl create certificaterequest test --from-certificate-file=cert.yaml` | 파일에서 인증서 요청 생성 |
| `cmctl convert --output-format=pem --input-file=cert.yaml` | 인증서를 PEM 형식으로 변환 |
| `cmctl experimental create acmeaccount --server=<url> --email=<email>` | ACME 계정 등록 테스트 |
| `kubectl annotate certificate <name> cert-manager.io/issue-temporary-certificate="true" --overwrite` | 즉시 인증서 갱신 |
| `kubectl delete certificaterequest <name>` | 실패한 인증서 요청 제거 |
| `kubectl delete order <name>` | ACME 주문 삭제 |
| `kubectl delete challenge <name>` | ACME 챌린지 제거 |
| `kubectl get certificate <name> -o jsonpath='{.status.conditions}'` | 인증서 상태 조건 추출 |
| `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` | 인증서 만료 날짜 확인 |
| `helm upgrade cert-manager jetstack/cert-manager --namespace cert-manager --version v1.13.3` | cert-manager를 새 버전으로 업그레이드 |
| `kubectl rollout restart deployment -n cert-manager` | cert-manager의 모든 구성 요소 재시작 |
| `kubectl scale deployment cert-manager -n cert-manager --replicas=2` | 고가용성을 위한 cert-manager 확장 |
| `kubectl get certificate --watch` | 실시간으로 인증서 상태 변화 확인하기 |
| `kubectl patch certificate <name> --type merge -p '{"spec":{"renewBefore":"720h"}}'` | 인증서 갱신 창 수정 |
| `kubectl delete secret <tls-secret>` | 인증서 시크릿 삭제 (재생성 트리거) |
| `cmctl experimental install` | cmctl 도구를 사용하여 cert-manager 설치 |
| `cmctl experimental uninstall` | cert-manager를 제거하고 리소스 정리하기 |
```yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}
```## 기본 명령어
```yaml
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
    solvers:
    - http01:
        ingress:
          class: nginx
```## 고급 사용법
```yaml
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
    solvers:
    - dns01:
        cloudDNS:
          project: my-gcp-project
          serviceAccountSecretRef:
            name: clouddns-dns01-solver
            key: key.json
```## 구성
```yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: ca-issuer
  namespace: default
spec:
  ca:
    secretName: ca-key-pair
```### 자체 서명된 ClusterIssuer
```yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-com
  namespace: default
spec:
  secretName: example-com-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - example.com
  - www.example.com
  duration: 2160h      # 90 days
  renewBefore: 360h    # 15 days before expiry
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-cert
  namespace: default
spec:
  secretName: wildcard-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - "*.example.com"
  - example.com
```### Let's Encrypt 스테이징 (HTTP-01 챌린지)
```yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: vault-issuer
  namespace: default
spec:
  vault:
    server: https://vault.example.com
    path: pki/sign/example-dot-com
    auth:
      kubernetes:
        mountPath: /v1/auth/kubernetes
        role: cert-manager
        secretRef:
          name: vault-token
          key: token
# custom-values.yaml
installCRDs: true
replicaCount: 2

resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    cpu: 200m
    memory: 256Mi

prometheus:
  enabled: true
  servicemonitor:
    enabled: true

webhook:
  replicaCount: 2

cainjector:
  replicaCount: 2
```### Let's Encrypt 프로덕션 (DNS-01 챌린지)
```bash
# Create ClusterIssuer
kubectl apply -f - <<EOF
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
    solvers:
    - http01:
        ingress:
          class: nginx
EOF

# Create Ingress with TLS annotation
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - example.com
    secretName: example-com-tls
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: example-service
            port:
              number: 80
EOF

# Verify certificate creation
kubectl get certificate
kubectl describe certificate example-com-tls
# Create self-signed CA
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-ca
  namespace: cert-manager
spec:
  isCA: true
  commonName: my-ca
  secretName: my-ca-secret
  privateKey:
    algorithm: ECDSA
    size: 256
  issuerRef:
    name: selfsigned-issuer
    kind: ClusterIssuer
EOF

# Create CA issuer from generated CA
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: my-ca-issuer
spec:
  ca:
    secretName: my-ca-secret
EOF

# Issue service certificates
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: service-a-cert
  namespace: default
spec:
  secretName: service-a-tls
  duration: 8760h
  renewBefore: 720h
  subject:
    organizations:
    - my-org
  commonName: service-a.default.svc.cluster.local
  dnsNames:
  - service-a.default.svc.cluster.local
  issuerRef:
    name: my-ca-issuer
    kind: ClusterIssuer
EOF
```### CA 발급자 (내부 PKI)
```bash
# Create DNS provider secret (example: Cloudflare)
kubectl create secret generic cloudflare-api-token \
  --from-literal=api-token=YOUR_CLOUDFLARE_API_TOKEN

# Create ClusterIssuer with DNS-01 solver
kubectl apply -f - <<EOF
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
    solvers:
    - dns01:
        cloudflare:
          email: admin@example.com
          apiTokenSecretRef:
            name: cloudflare-api-token
            key: api-token
EOF

# Request wildcard certificate
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-example
  namespace: default
spec:
  secretName: wildcard-example-tls
  issuerRef:
    name: letsencrypt-dns
    kind: ClusterIssuer
  dnsNames:
  - "*.example.com"
  - example.com
EOF

# Monitor certificate issuance
kubectl get certificate wildcard-example -w
# Create certificate for webhook
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: webhook-cert
  namespace: webhook-system
spec:
  secretName: webhook-server-cert
  duration: 8760h
  renewBefore: 720h
  issuerRef:
    name: selfsigned-issuer
    kind: ClusterIssuer
  dnsNames:
  - webhook-service.webhook-system.svc
  - webhook-service.webhook-system.svc.cluster.local
EOF

# Reference in webhook configuration
kubectl apply -f - <<EOF
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: my-webhook
  annotations:
    cert-manager.io/inject-ca-from: webhook-system/webhook-cert
webhooks:
- name: webhook.example.com
  clientConfig:
    service:
      name: webhook-service
      namespace: webhook-system
      path: "/validate"
    caBundle: "" # Injected by cert-manager
EOF
```### 인증서 리소스
```bash
# Create certificate with short duration for testing
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: short-lived-cert
  namespace: default
spec:
  secretName: short-lived-tls
  duration: 24h
  renewBefore: 8h
  issuerRef:
    name: selfsigned-issuer
    kind: ClusterIssuer
  dnsNames:
  - test.example.com
EOF

# Monitor renewal
kubectl get certificate short-lived-cert -w

# Force immediate renewal
kubectl annotate certificate short-lived-cert \
  cert-manager.io/issue-temporary-certificate="true" \
  --overwrite

# Check renewal history
kubectl get certificaterequest -l cert-manager.io/certificate-name=short-lived-cert

# Verify new certificate
cmctl inspect secret short-lived-tls

renewBefore### 와일드카드 인증서 certmanager_certificate_expiration_timestamp_seconds

  • DNS-01을 와일드카드 및 내부 서비스에 사용: DNS-01 챌린지는 와일드카드 인증서에 필요하며 인터넷에 노출되지 않은 서비스에 더 잘 작동합니다

  • 적절한 RBAC 구현: Kubernetes RBAC을 사용하여 발급자 및 인증서 시크릿에 대한 접근을 제한하여 무단 인증서 생성 방지

  • 구성의 버전 관리: Git에 인증서 및 발급자 매니페스트를 저장하여 변경 사항 추적 및 GitOps 워크플로 활성화

  • 환경별 별도의 발급자 사용: 개발/스테이징/프로덕션을 위해 다른 발급자를 생성하여 자격 증명 격리 및 환경 간 인증서 문제 방지

  • 웹훅에 대한 CA 주입 활성화: 웹훅 구성에 CA 번들을 자동으로 주입하려면 cert-manager.io/inject-ca-from어노테이션 사용

  • 재해 복구 계획: Kubernetes 시크릿에 저장된 CA 개인 키 및 ACME 계정 자격 증명을 외부 보안 저장소에 백업

문제 해결

문제솔루션
Certificate stuck in “Pending”Check certificate request: kubectl describe certificaterequest <name>. Look for ACME challenge failures or issuer configuration errors
ACME HTTP-01 challenge failingVerify ingress is accessible: curl http://<domain>/.well-known/acme-challenge/test. Check ingress class matches solver configuration
DNS-01 challenge timeoutConfirm DNS provider credentials: kubectl get secret <dns-secret> -o yaml. Verify DNS propagation: dig TXT _acme-challenge.<domain>
”Too many certificates” rate limitLet’s Encrypt 스테이징 서버로 전환하거나 7일을 기다리세요. 요율 제한 확인: https://letsencrypt.org/docs/rate-limits/
Certificate not renewing automaticallyCheck renewBefore setting and cert-manager logs: kubectl logs -n cert-manager deployment/cert-manager. Verify controller is running
Webhook connection failuresVerify webhook service is running: kubectl get svc -n cert-manager. Check webhook certificate validity: cmctl check api
CA injection not workingEnsure cainjector is running: kubectl get pods -n cert-manager. Verify annotation syntax: cert-manager.io/inject-ca-from: namespace/certificate
Certificate shows “Ready=False”Get detailed status: cmctl status certificate <name>. Check events: kubectl get events --field-selector involvedObject.name=<cert-name>
Order stuck in “Pending”Delete order to retry: kubectl delete order <order-name>. Certificate controller will create new order automatically
Secret not created after certificate readyCheck secret name matches secretName in Certificate spec. Verify namespace: kubectl get secret <name> -n <namespace>
Wildcard certificate validation failsDNS-01 솔버가 구성되었는지 확인하세요 (HTTP-01은 와일드카드를 지원하지 않습니다). TXT 레코드 생성을 위한 DNS 제공자 권한을 확인하세요
Certificate shows wrong issuerDelete certificate request: kubectl delete certificaterequest <name>. Update Certificate spec with correct issuerRef
High memory usageReduce certificate count or increase resources: kubectl set resources deployment cert-manager -n cert-manager --limits=memory=512Mi
Duplicate certificates createdCheck for multiple Certificate resources with same secretName. Remove duplicates to prevent conflicts
ACME account registration fails발급자 사양에서 이메일 형식을 확인하세요. ACME 서버 URL이 올바른지 확인하세요. 자세한 오류 메시지를 위해 cert-manager 로그를 검토하세요
# Complete troubleshooting workflow
kubectl describe certificate <cert-name>
kubectl get certificaterequest -l cert-manager.io/certificate-name=<cert-name>
kubectl describe certificaterequest <request-name>
kubectl get order
kubectl describe order <order-name>
kubectl get challenge
kubectl describe challenge <challenge-name>
kubectl logs -n cert-manager deployment/cert-manager --tail=100
```[No text provided]

Would you like me to clarify or complete the missing texts?```bash
# Search for specific certificate errors
kubectl logs -n cert-manager deployment/cert-manager | grep "certificate=<cert-name>"

# Find ACME challenge errors
kubectl logs -n cert-manager deployment/cert-manager | grep "challenge"

# Check for rate limit errors
kubectl logs -n cert-manager deployment/cert-manager | grep "rate limit"

# Monitor certificate renewal attempts
kubectl logs -n cert-manager deployment/cert-manager -f | grep "renewal"