Cert-Manager + Let’s Encrypt 사용 K8s에서 SSL 적용 튜토리얼

이 포스트에서는 쿠버네티스 환경 내부에서 https 통신을 하기 위한 인증서를 생성하고 자동으로 갱신해주는 Cert-Manager 라는 모듈과 Let’s Encrypt 를 사용하여 인증서를 발급하는 방법에 대한 가이드를 소개합니다.

해당 포스트에서는 Ingress Controller는 NGINX Plus Ingress Controller를 사용하며, Cert-Manager의 설치 및 배포하는 과정은 다루지 않습니다. Cert-Manager 설치에 대한 가이드는 여기를 클릭하여 확인하세요.

이 포스트에서의 테스트 환경은 다음과 같습니다:

  • Kubernetes Client Version: v1.28.2
  • Kubernetes Server Version: v1.28.9
  • NGINX Plus Ingress Controller v3.5.0
  • Ubuntu 22.04.3 LTS
  • Cert-Manager 1.14.4

목차

1. Service & Deploy 리소스 배포
2. Cert-Manager Issuer 리소스 생성
3. VirtualServer 리소스 생성
4. 발급된 인증서 확인

1. Service & Deploy 리소스 배포

SSL 인증서 발급을 하기 전, 테스트하기 위해 NGINX 이미지를 사용하여 간단한 Service와 Deployment 리소스를 배포합니다:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy1
  namespace: nginx-ingress
spec:
  selector:
    matchLabels:
      app: deploy1
  template:
    metadata:
      labels:
        app: deploy1
    spec:
      containers:
      - name: containerd1
        image: nginx
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: svc1
  namespace: nginx-ingress
spec:
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
    name: http
  selector:
    app: deploy1

위에 작성한 파일을 배포 및 확인합니다.

$ kubectl apply -f service.yaml
deployment.apps/deploy1 created
service/svc1 created

$ kubectl get pods -n nginx-ingress
NAME                             READY   STATUS    RESTARTS   AGE
deploy1-xxxxxxx-yyyyyyy          1/1     Running   0          44s

2. Cert-Manager Issuer 리소스 생성

Issuer 리소스에 대해 간단히 설명하자면,

Issuer는 Cert-Manager가 TLS 인증서를 요청하는 방법을 정의합니다. Issuer 리소스는 쿠버네티스의 단일 Namespace에만 적용됩니다. 해당 포스트에서는 nginx-ingress라는 Namespace에 배포합니다. (TLS 인증서를 클러스터에 적용시키고 싶으시다면 ClusterIssuer 리소스를 사용하시면 됩니다.)

해당 테스트에서는 프로덕션용 인증서를 발급합니다. Issuer 리소스 내용은 다음과 같습니다:

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: letsencrypt-prod
  namespace: nginx-ingress
spec:
  acme:
    # The ACME server URL
    server: https://acme-v02.api.letsencrypt.org/directory
    # Email address used for ACME registration
    email: admin@example.com
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
      name: letsencrypt-prod
    # Enable the HTTP-01 challenge provider
    solvers:
      - http01:
          ingress:
            ingressClassName: nginx

위에서 작성한 Issuer 리소스를 배포 및 확인합니다.

$ kubectl apply -f letsencrypt-prod.yaml
issuer.cert-manager.io "letsencrypt-prod" created

$ kubectl get issuer -n nginx-ingress
NAME               READY   AGE
letsencrypt-prod   True    145m

스테이징용 Issuer 리소스는 아래와 같습니다:

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: letsencrypt-staging
  namespace: nginx-ingress
spec:
  acme:
    # The ACME server URL
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    # Email address used for ACME registration
    email: admin@example.com
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
      name: letsencrypt-staging
    # Enable the HTTP-01 challenge provider
    solvers:
      - http01:
          ingress:
            ingressClassName: nginx

3. VirtualServer 리소스 생성

해당 테스트에서는 Ingress 리소스가 아닌 NGINX Plus Ingress Controller의 커스텀 리소스인 VirtualServer 리소스를 사용합니다.

해당 테스트에서는 hodevops.nginxstore.kr이라는 DNS를 사용하며, VirtualServer 리소스의 내용은 다음과 같습니다:

apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: hodevops
  namespace: nginx-ingress
spec:
  host: hodevops.nginxstore.kr
  tls:
    cert-manager:
      issuer: letsencrypt-prod      # 위에서 작성한 Issuer 리소스 이름
    secret: quickstart-example-tls  # 발급받을 Secret 이름
  ingressClassName: nginx
  upstreams:
  - name: default
    service: svc1
    port: 80
  routes:
  - path: /
    action:
      pass: default

spec.tls.cert-manager 오브젝트는 기본적으로 NGINX Plus Ingress Controller에서 비활성화 되어있습니다. NGINX Plus Ingress Controller의 Deployment 리소스에서 아래와 같이 활성화합니다.

...   
        args:
          - -nginx-plus
          - -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
          - -enable-cert-manager
...

4. Cert-Manager 가 발급한 인증서 확인

위에서 생성한 Issuer 리소스와 VirtualServer 리소스를 배포하게 되면 Secret, Certificate, CertificateRequest, Order, Challenge 등 Let’s Encrypt 에서 인증서 발급을 위한 검증 리소스들이 생성이 됩니다.

위 Issuer 리소스를 작성할 때 이번 테스트에서는 ACME HTTP-01 유형을 사용했습니다. 이 유형으로 인증서를 발급받기 위해서는 Let’s Encrypt가 위에서 지정한 DNS의 80포트로 접근이 가능해야 합니다.

모든 검증이 끝나게 되면 아래 명령어를 통해서 인증서 발급이 됐는지 확인할 수 있습니다:

$ kubectl get certificate -n nginx-ingress
NAME                     READY   SECRET                   AGE
quickstart-example-tls   True    quickstart-example-tls   163m

또한 위의 VirtualServer 리소스에서 정의한 Secret을 확인하려 tls.key와 tls.crt가 정상적으로 발급되었는지 아래 명령어를 통해 확인할 수 있습니다.

$ kubectl describe secret quickstart-example-tls -n nginx-ingress
...
Data
====
tls.crt:  3611 bytes
tls.key:  1679 bytes

정상적으로 발급이 완료되었다면, https로 접속하여 확인합니다.

인증서가 잘 적용된 것을 확인할 수 있습니다.

NGINX Plus를 직접 사용해 보시려면 30일 무료 평가판을 신청하거나 NGINX STORE에 연락하여 논의하십시오.

NGINX STORE를 통한 솔루션 도입 및 기술지원 무료 상담 신청

* indicates required