티스토리 뷰

이번 포스팅은 Kubernetes를 운영하면서 어플리케이션에 HTTPS 이슈가 발생하여 해결한 내용을 공유하고자 합니다.. 어떻게 보면 정말 간단하고 Kubernetes networking을 잘 알면 바로 해결할 수 있는 부분이지만, 누군가에게는 도움이 되고자 하는마음에,,

 

먼저 외부에서 Kubernetes안에서 실행되는 Pod 즉 어플리케이션에 접속하려면 Ingress가 필요합니다. 클라이언트가 HTTP / HTTPS 요청을 Ingress에 보낼 때, 요청한 호스트와 경로에 따라 요청을 전달할 서비스가 결정됩니다. Ingress는 네트워크 스택의 어플리케이션 계층(HTTP Layer Control) 7에서 작동하며 서비스가 할 수 없는 쿠키 기반 세션 어피니티 등과 같은 기능을 제공합니다. 

 

hskim.example.com이라는 호스트 명으로 접근하는 네트워크 요청에 대해 아래 ingress 포맷을 적용하는데 http 프로토콜을 통해 경로 목록인 /testpath라는 경로로 접근하는 요청을 포트는 80 test라는 서비스로 전달하는 뜻입니다. 아래에는 경로 유형을 따로 표기하지 않았지만 지원되는 경로 유형은 ImplementationSpecific, Exact, Prefix 3가지입니다. 또한, ingress는 동일한 IP 주소에서 여러 호스트 이름으로 트래픽을 라우팅할 수 있습니다. 

 

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: hskim.example.com
  - http:
      paths:
      - path: /testpath
        backend:
          serviceName: test
          servicePort: 80

해당 요청처럼 Ingress를 생성하면 끝나는 것이 아니라 Ingress Controller에 적용 되어야지만 Ingress에 적용된 규칙이 활성화 됩니다. 아래는 상세하게 Ingress 동작 방식을 설명합니다.

 

TIP. Ingress 컨트롤러는 bypassing이라는 기능을 통하여 application Pod에 트래픽을 전달합니다. 해당 Pod의 Service를 경유해야 하는 네트워크 홉을 줄이게 됩니다.

 

클라이언트가 인그레스 컨트롤러로 파드에 연결하는 방식입니다. 클라이언트는 먼저 hskim.example.com의 DNS 조회를 수행하고 DNS 서버가 Ingress 컨트롤러의 IP를 반환합니다. 그런 다음 클라이언트는 HTTP 요청을 Ingress 컨트롤러로 전송하고 host 헤더에서 hskim.example.com을 지정합니다. 컨트롤러는 해당 헤더에서 클라이언트가 액세스하려는 서비스를 결정하고 서비스와 관련된 엔드포인트 오브젝트로 Pod IP를 조회한 다음 클라이언트 요청을 Pod에 전달합니다.

 

위에는 일반적으로 HTTP 트래픽을 전달할때의 방식입니다. HTTPS 트래픽을 처리 할수 있도록 Ingress에 TLS를 적용할 수 있습니다. TLS를 적용하기 전에, 이슈를 경험한걸 간단히 설명드리겠습니다. 어플리케이션에 HTTPS로 접근했을시에는 정상적으로 HTTPS로 통신이 되지만 HTTP로 애플리케이션에 접근했을때는 HTTPS로 Redirection 되지 않고 HTTP로 되는것을 발견하였습니다.

 

Pod는 nginx service를 하고 있는 어플리케이션이었고 nginx.conf파일은 다음과 같습니다.

location = / {
      return 301 https://hskim.example.com;
    }

 

현재 아래 그림처럼 Public Cloud에서 LB를 사용해 인증서는 LB에 적용하고 서버포트는 Ingress 컨트롤러 서비스의 Port를 입력하여 맵핑했습니다. nginx는 HTTP로 떠있는 상태에서 nginx log를 보니 HTTP이니 HTTPS로 Redirection하라며 301,302 Code를 발견하였습니다. 즉, 왜인지 모르겠지만 Public Cloud LB에 인증서가 제대로 적용이 안된건지,, HTTPS로 nginx Pod에 전달해야하는데 HTTP로 전달하여 nginx Pod는 HTTP로 왔으니 nginx conf파일의 해당 location 규칙을 적용하여 HTTPS로 Redirection하라고 지시하고 아래 그림의 3번 4번이 계속해서 반복되는 현상 무한루프가 돌았습니다. 또한 웹브라우저에서 직접 개발자모드로 확인했을 시 301,302 코드가 계속 번갈아 보이면서 무한루프가 돌고 있다는걸 확신했습니다.

TIP. 301, 302 코드는 HTTP Response Status Code로 요청에 대한 웹서버의 응답을 나타내는 코드를 말합니다. 301과 302코드는 사용자를 새로운 URL로 이동시키는 코드입니다. 또한, 301과 302는 "3XX Redirection"클래스에 속합니다. Redirection 클래스에 속하는 상태코드들은 클라이언트를 지정된 위치로 이동시키거나 참조하게 하는 등의 동작을 말합니다. 브라우저가 Redirection 상태코드를 만나면 대부분 새로운 URL로 이동하게 됩니다.

 

TLS를 적용하기 전에 nginx ingress annotations를 활용하여 옵션값을 줘서 적용해봤지만 동일한 문제가 발생했습니다. 제가 잘못알고 쓰는건지,, 했지만 위의 무한루프 사실을 알고 해당 annotations는 무의미하다고 뒤늦게 깨닳았습니다.. 일단 테스트해본 옵션값에 대한 간단한 설명은 다음과 같습니다.

  • nginx.ingress.kubernetes.io/app-root > 어플리케이션의 루트 정의
  • nginx.ingress.kubernetes.io/force-ssl-redirect > http로 접속했을때 강제로 https로 Redirect(308) 하는 옵션
  • nginx.ingress.kubernetes.io/ssl-redirect > ssl을 허용할 수 있는지 여부를 나타냄(ingress에 인증서가 포함 된 경우 기본값은 True)

따라서 아래와 같이 LB에는 인증서를 적용하지 않고 TCP로 Bypass만 하고 Ingress에 TLS를 적용하였습니다. 이제 정상적으로 nginx Pod에 HTTP가 아닌 HTTPS로 요청이 들어와 해당 nginx conf파일의 location 규칙은 실행되지 않고 외부에서 HTTP / HTTPS 어느 요청이 들어와도 정상적으로 HTTPS로 Pod가 실행되었습니다.

TLS는 아래와 같이 인증서를 가지고 Secret에 저장하면 Ingress 매니페스트에서 참조합니다. 현재 Certbot에서 인증서를 발급받고 있으므로 아래와 같이 privkey.pem과 fullchain.pem을 활용해서 Secret를 설정해줍니다. Secret은 Namspace에 대해 디펜던시가 걸려있습니다.

kc create -n hskim secret tls hskim-secret --key privkey.pem --cert fullchain.pem
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: hskim.example.com
  - http:
      paths:
      - path: /testpath
        backend:
          serviceName: test
          servicePort: 80
  tls:
  - hosts:
    - hskim.example
    secretName: hskim-secret          
댓글
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30