반갑습니다. 저는|기업가이자, 엔지니어입니다.
k8s 이용해서 웹 서버 구축하기 - 4부. nginx ingress 에 https 적용 (cert-manager 이용)

k8s 이용해서 웹 서버 구축하기 - 4부. nginx ingress 에 https 적용 (cert-manager 이용)

Tags
k8s
k3s
Linux
Published
발행일 - 2022년 9월 1일
Author
Eugene Jeon (전유진)
AuthorLink

 
 

개요

실제 운영되는 서비스에는 HTTP 프로토콜을 그대로 사용하는 경우는 드물다. 보안에 취약하기 때문이다. TLS(SSL) 인증서를 발급받고 이를 이용하여 HTTPS 프로토콜을 주로 사용한다.
 
이를 위해서는 Ingress 에 TLS 설정을 추가해 주어야 한다.
많이 사용하는 것 중에는 LetsEncrypt 가 있다. 여기서 인증서를 발급받고 적용할 수 있다. 단, 3개월 마다 갱신인증을 해 주어야 한다.
 
그래서 cert-manager 를 사용하여 자동갱신을 하도록 하자.
 

Cert-Manager 설치

(yaml)
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.yaml
 
💡
만약, no kind "ClusterIssuer" is registered for version "cert-manager.io/v1" in scheme 이라는 오류가 보인다면, helm 을 이용하여 CRDs 를 함께 설치하면 된다.
(shell)
helm repo add jetstack https://charts.jetstack.io && \ helm repo update && \ helm install \ cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --version v1.9.1 \ --set installCRDs=true # 아래는 GKE, EKS 등에서 Custom CNI 를 사용한다면 적용! # https://cert-manager.io/docs/installation/compatibility/ #--set webhook.hostNetwork=true \ #--set webhook.securePort=10260
 

cluster-issuer 생성

Issuer 와 ClusterIssuer 가 존재한다. 이 둘의 차이는 네임스페이스 범위인가, 클러스터 범위인가에 있다. 꼭! 참고하도록 한다. 발급에는 staging, prod 두 가지가 있으니 이 또한 주의하도록 한다.
 
(yaml)
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-staging spec: acme: # The ACME server URL server: https://acme-staging-v02.api.letsencrypt.org/directory # Email address used for ACME registration email: test@test.com # Name of a secret used to store the ACME account private key privateKeySecretRef: name: letsencrypt-staging # Enable the HTTP-01 challenge provider solvers: # An empty 'selector' means that this solver matches all domains - selector: {} http01: ingress: class: nginx --- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: # The ACME server URL server: https://acme-v02.api.letsencrypt.org/directory # Email address used for ACME registration email: test@test.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: class: nginx
 
  • 2 : Issuer 는 네임스페이스 범위이므로 ClusterIssuer 를 사용한다.
  • 4,13,26,35 : staging 과 prod 가 나뉜다.
  • 15-20, 37-40 : 만약 cloudfalre 를 이용한다면 아래와 같이 변경할 수 있다.
    • (yaml)
      # ... solvers: - dns01: cloudflare: email: <your-email> apiTokenSecretRef: name: cloudflare-api-token-secret key: <token>
 
최종적으로 작성한 Issuer/ClusterIssuer 를 실행하면된다.
(bash)
kubectl create -f cluster-issuer.yaml
 
확인은 아래 명령어로 할 수 있다.
(bash)
kubectl get clusterissuer
 
💡
생성 후에 timeout 등으로 dns 오류가 난다면, coredns 헬스체크를 해보자.
(shell)
COREDNSPOD1=$(kubectl get pod -n kube-system -l k8s-app=kube-dns -o jsonpath='{.items[0].status.podIP}') echo $COREDNSPOD1 && \ curl $COREDNSPOD1:8080/health; echo && \ curl $COREDNSPOD1:8181/ready; echo
 
💡
POD 을 생성한 후, nslookup 으로 테스트 해 볼 수 도 있다.
(shell)
# 파드 생성 kubectl run -it --rm netdebug --image=nicolaka/netshoot --restart=Never -- zsh ------------- # 파드에서 네임서버 확인 cat /etc/resolv.conf nameserver 10.96.0.10 search default.svc.cluster.local svc.cluster.local cluster.local options ndots:5 # 도메인 쿼리 기본 방식 : ndots:5 설정으로 최종 호출 전에 설정되어 있는 검색 도메인(search)을 추가하여 먼저 쿼리 호출 nslookup -type=A -debug google.com # | grep QUESTIONS -A1
 
💡
그래도 안된다면, 방화벽을 확인하자! 테스트할 때는 잠시 꺼두어도 좋다.

Ingress 에 인증서 적용

공식 문서를 보면, 버전마다 조금씩 다르고 사용방법도 조금씩 다르다. 대표적인 방법 두 가지로 나누어 작성하겠다. (참고로 두 번째 방법이 조금 더 간단하다.)

1. Certificate 작성 → 실행 → 적용

(yaml)
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: <certificate-name> namespace: <ACC-deployment-namespace> spec: secretName: <certificate-secret-name> duration: 2160h # 90d renewBefore: 360h # 15d commonName: 'test.domain.com' dnsNames: # 사용하고 발급할 도메인 입력 - 'test.domain.com' - 'test2.domain.com' issuerRef: kind: ClusterIssuer name: letsencrypt-staging # issuer 이름이므로 변경해야 한다.
 
💡
Wildcard Domain SSL (*.domain.com) 인증서를 발급받을 수 도 있다.
[열기] Wildcard Domain 발급하기!
(yaml)
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: <certificate-name> namespace: <ACC-deployment-namespace> spec: secretName: <certificate-secret-name> duration: 2160h # 90d renewBefore: 360h # 15d # 사용하고 발급할 도메인 입력 #commonName: domain.com dnsNames: - domain.com - '*.domain.com' issuerRef: kind: ClusterIssuer name: letsencrypt-staging # issuer 이름이므로 변경해야 한다.
 
💡
주의! 최근 업데이트로 와일드카드에 대한 오류가 있는 듯 하다. https://stackoverflow.com/questions/68219076/cert-manager-no-configured-challenge-solvers-can-be-used-for-this-challenge
 
작성한 파일을 실행하는 순간, let’s encrypt 로 인증서 생성을 요청한다.
(bash)
kubectl create -f certificate.yaml
 
아래 명령어로 인증서 상태를 확인할 수 있다.
(bash)
kubectl get certificate
 
💡
만약, READY 상태가 False 라고 나온다면, 도메인 소유 검증을 실패한 것일 수 도 있다. (주의!)
 
이제 Ingress 에서 hosts 부분과, secretName 부분을 수정하면 된다.
(yaml)
# ... spec: tls: - hosts: - test.domain.com secretName: <certificate-name> # 인증서 이름을 입력하면된다. # ...
 

2. Ingress 에 바로 적용

이 때는 annotations 부분과 tls 부분을 함께 수정해야 한다.
(yaml)
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: web-ingress annotations: nginx.ingress.kubernetes.io/ssl-redirect: "true" # kubernetes.io/ingress.class: nginx # 아래 ingressClassName 으로 대체 kubernetes.io/tls-acme: "true" cert-manager.io/cluster-issuer: letsencrypt-prod # ClusterIssuer 이름 nginx.ingress.kubernetes.io/backend-protocol: HTTPS spec: ingressClassName: nginx tls: - hosts: - test.domain.com # 인증서를 적용할 도메인으로 변경 secretName: <certificate-name> # 인증서 key가 저장되는 secret rules: - host: test.domain.com # 인증서를 적용할 도메인으로 변경 http: paths: - path: / backend: serviceName: web servicePort: 443 status: loadBalancer: ingress: - {}
 
💡
참고로, kubernetes/nginx-ingress 와 nginx/nginx-ingress 는 다른 것이다. HTTPS 를 적용하고 싶다면, kubernetes/nginx-ingress 를 설치해서 사용하도록 하자.
 

Loading Comments...