메인 콘텐츠로 이동하기
  1. Posts/

[K3s-05] K3s ingress에 TLS 인증서 발급 자동화

·573 자

Let's encryptcert-manager를 사용하면 우리의 k3s 클러스터에 TLS 인증서를 첨부할 수 있습니다. helm을 사용하여 cert-manager를 설치합니다. 이 게시글에서는 helm의 설치 방법과 helm이 무엇인지 설명하지 않겠습니다. 만약 helm이 설치되어 있지 않다면 helm 문서를 참조하세요.

helm repo add jetstack https://charts.jetstack.io
helm repo update

curl -L -o cert-manager.yaml https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.crds.yaml
kubectl apply -f cert-manager.yaml

helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.8.0

kubectl get pods -n cert-manager

먼저, 전체 네임스페이스에서 접근할 수 있는 ClusterIssuer를 생성합니다. 또한 Cloudflare API 토큰을 저장하는 k3s secret을 생성합니다. 이 Cloudflare API 토큰은 dns-01 챌린지에서 DNS zone을 편집할 수 있는 접근 권한을 있어야 합니다. AWS의 Route53을 사용하는 경우, 이 블로그(와일드카드 인증서와 관련된 미디엄 블로그)에 자세히 기술되어 있습니다. 따라서 기본적으로는 현재 DNS를 설정하기 위해 사용하고 있는 Cloud provider를 먼저 알아내는 합니다. cert-manager가 지원하는 DNS 제공업체의 상세 목록은 acme dns01관련된 cert-manager 설정에 기재되어 있습니다.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-stg
spec:
  acme:
    email: [email protected]
    # let's encrypt staging 환경
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      # 계정의 개인 키를 저장할 Secret 리소스
      name: le-issuer-acct-key
    solvers:
    - dns01:
        cloudflare:
          email: [email protected]
          apiTokenSecretRef:
            name: cloudflare-api-token-secret
            key: api-token
      selector:
        dnsZones:
        - 'jaehong21.com'
        - '*.jaehong21.com'
       
---
apiVersion: v1
kind: Secret
metadata:
  name: cloudflare-api-token-secret
  namespace: cert-manager
type: Opaque
stringData:
  api-token: <cloudflare-api-token>

그런 다음 kubectl get clusterissuer -A로 발행자의 상태 ReadyTrue인지 확인하세요. 이 작업은 시간이 조금 걸릴 수 있습니다.

! 중요: https://letsencrypt.org/docs/staging-environment/
위의 예제는 Let’s Encrypt의 스테이징 환경을 사용하는 것으로, 인증서 발급에 대한 속도 제한이 없습니다. 브라우저에서 신뢰할 수 있는(유효한) 인증서를 받고자 할 때는 위 URL을 https://acme-v02.api.letsencrypt.org/directory로 교체해야 합니다.

이제 기존 ClusterIssuer를 사용하여 인증서를 생성합니다. dns-01 challenge를 이용할 때는 와일드카드 인증서를 발급받을 수 있지만, http-01 challenge를 사용하는 경우에는 와일드카드 인증서를 획득하기 어려우며, 발급받고자 하는 인증서의 특정 URL을 직접 명시해주어야합니다.

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: le-jaehong21-com
  namespace: default
spec:
  secretName: le-jaehong21-com
  issuerRef:
    name: letsencrypt-stg
    kind: ClusterIssuer
  commonName: '*.jaehong21.com'
  dnsNames:
    - "*.jaehong21.com"
# 인증서가 생성되었는지 확인 
# 처음에는 `Ready` 상태가 `False`입니다
kubectl get certs -A

# 아래 명령어로 인증서 발급 진행 상황을 확인할 수 있습니다 
# 완료되면 리소스가 표시되지 않습니다
kubectl get challenges -A

# 이후에 인증서의 `Ready`도 `True`인지 다시 확인하세요

(Cloudflare) 대시보드를 확인하여 dns-01 챌린지와 함께 사용되는 호스팅 존에 TXT 레코드가 추가되었는지 진행 상황을 볼 수도 있습니다.

Finally, implement the tls secret that is created with certificate to the ingress.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: traefik-ingress
  annotations:
    traefik.ingress.kubernetes.io/router.tls: "true"
spec:
  ingressClassName: traefik
  rules:
    - host: k3s.jaehong21.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx-deployment
                port:
                  number: 80

  tls:
  - hosts:
      - k3s.jaehong21.com
    secretName: le-jaehong21-com

Cloudflare Origin CA #

저의 경우에는 Cloudflare에서 DNS 레코드들을 관리하고 있습니다. Cloudflare는 Let’s Encrypt에 비해 훨씬 긴 만료 날짜의 인증서를 발급할 수도 있습니다.

kubectl create secret generic k3s-tls-secret --from-file=tls.crt=./server.crt --from-file=tls.key=./server.key --namespace dev
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: traefik-ingress
  annotations:
    traefik.ingress.kubernetes.io/router.tls: "true"

spec:
  ingressClassName: traefik
  rules:
    - host: k3s.jaehong21.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx-deployment
                port:
                  number: 80
  tls:
    - secretName: k3s-tls-secret

그러나 Origin CA는 Cloudflare Network 자체에서만 유효한 자체 서명 인증서(Self-signed certifiacte)입니다. 따라서 아래 예와 같이 프록시 설정을 이용하여, Cloudflare Network를 거칠 수 있도록 해야 합니다. 이 경우 요청이 Cloudflare Network를 통해 전송되므로 LAX 위치를 통해 다시 라우팅될 수 있습니다.

resource "cloudflare_record" "k3s_test" {
  zone_id = var.jaehong21_com.zone_id
  name    = "k3s"
  value   = "43.202.242.99"
  proxied = true
  type    = "A"
  ttl     = 1
}

위 예시처럼, terraform으로 Cloudflare DNS 레코드를 관리하는 경우, terraform cloudflare 제공자를 최신 버전으로 업그레이드해야 합니다(최소한 버전 4 이상). 버전 3에서는 terraform에서 proxied 값을 true로 수정하고 유지하는 데 버그가 있었습니다.

Reference #