4장 Istio gateways: Getting traffic into a cluster
개발 환경
◎ 이전에 k8s 배포, istio 설치는 생략하고 아래 내용 중점으로 실습 할 예정 입니다.
항목 내용 Device MackBook Pro Chip Apple M2 OS Sequoia 15.4 kind(k8s) v1.23.17 istio v1.178
- Defining entry points into a cluster 클러스터 진입 지점 정의,
- Routing ingress traffic to deployments in your cluster 인입 트래픽을 클러스터 내 배포로 라우팅하기
- Securing ingress traffic 인입 트래픽 보호하기 (HTTPS, x.509)
- Routing non HTTP/S traffic HTTP아닌 트래픽 라우팅 (TCP)
K8S 컨트롤 플레인 구성 NodePort(30000 HTTP, 30005 HTTPS)
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30000 # Sample Application (istio-ingrssgateway) HTTP
hostPort: 30000
- containerPort: 30001 # Prometheus
hostPort: 30001
- containerPort: 30002 # Grafana
hostPort: 30002
- containerPort: 30003 # Kiali
hostPort: 30003
- containerPort: 30004 # Tracing
hostPort: 30004
- containerPort: 30005 # Sample Application (istio-ingrssgateway) HTTPS
hostPort: 30005
- containerPort: 30006 # TCP Route
hostPort: 30006
- containerPort: 30007 # New Gateway
hostPort: 30007
networking:
podSubnet: 10.10.0.0/16
serviceSubnet: 10.200.1.0/24
1 . Traffic ingress concepts 트래픽 인그레스 개념
ingress
- 네트워크 연결하는 상황을 설명 하는 용어를 인그레이스 포인트 ingress point 라고 한다.
- 인그레스 ingress 란 네트워크 외부에서 발원해 네트워크 내부 엔드포인트를 향하는 트래픽을 말한다.
- 트래픽은 먼저 네트워크 내부로 향하는 트래픽에 문지기 역할을 하는 인그레스 포인트로 라우팅된다.
- 인그레스 포인트는 어떤 트래픽을 로컬 네트워크로 허용할지에 대한 규칙과 정책을 집행한다.
- 인그레스 포인트가 트래픽을 허용하면 로컬 네트워크의 올바른 엔드포인트로 트래픽을 프록시한다.
- 트래픽이 허용되지 않으면 인그레스 포인트는 트래픽을 거부한다.
1.1 Virtual IPs: Simplifying services access 가상IP: 서비스 접근 단순화
- 서비스 공개를 위한 DNS 구성 흐름
- 요구사항
- 우리 카탈로그에 있는 상품 목록을 외부 시스템이 가져갈 수 있도록 api.istioinaction.io/v1/products 에 노출하고 싶은 서비스 있다.
- 클라이언트가 그 엔드포인트를 쿼리하려고 할 때, 클라이언트의 네트워킹 스택은 먼저 api.istioinaction.io 도메인 이름을 IP 주소로 해석하려고 한다.
- DNS 서버로 수행된다. 네트워킹 스택은 DNS 서버에 특정 호스트네임의 IP 주소를 물어본다.
- 트래픽을 네트워크로 들여오는 작업의 첫 단계는 서비스 IP를 DNS의 호스트네임에 대응시킨다.
- 공개 주소의 경우에는 Amazon Route 53 이나 구글 Cloud DNS를 사용해 도메인 이름을 IP 주소로 대응시킬 수 있다.
- 자체 데이터센터에서는 내부 DNS 서버를 사용해 마찬가지 작업을 할 수 있다.
- 요구사항
그러면 어떤 IP 주소를 이 이름에 대응시켜야 할까? 아래 내용을 보면 알수 있다.
- 취약한 설계 방식
- 아래 그림은 "왜 도메인을 서비스의 단일 인스턴스나 엔드포인트(단일 IP)에 대응시키면 안 되는지" 를 보여준다.
- 이런 방식은 매우 취약할 수 있기 때문이다. "그 서비스 인스턴스가 다운되면 어떻게 되는가?"
- 동작하는 엔드포인트의 IP 주소로 DNS 매핑이 변결될 때까지 클라이언트는 많은 오류를 볼수 있다.
- 서비스가 다운될 때마다 그렇게 하는 것은 느리고, 오류가 발생하기 쉬우며, 가용성이 낮다.
- 운영 환경에 적합한 설계
- 아래 그림은 서비스를 대표하는 가상 IP 주소로 도메인 이름을 대응시키는 방법을 보여준다.
- 가상 IP 주소가 실제 서비스 인스턴스로 트래픽을 전달하므로 가용성과 유연성을 높일 수 있다는 이점이 있으며, 가상 IP는 리버스 프록시라는 인그레스 포인트 유형에 바인딩 된다.
- 리버스 프록시는 요청을 백엔드 서비스들에 분산시키는 역할을 하는 중간 구성 요소로, 특정 서비스에 해당하지 않는다.
- 리버스 프록시에는 로드 밸런싱 같은 기능도 있어 특정 백엔드 하나가 요청 때문에 과부하되지 않도록 할 수 도 있다.
1.2 Virtual hosting: Multiple services from a single access point 가상호스팅: 단일 접근 지점의 여러 서비스
- 서비스는 자체 IP를 지닌 서비스 인스턴스 여럿으로 구성될 수 있지만, 클라이언트는 오직 가상 IP만을 사용한다.
- 가상 IP 하나로 여러 호스트네임을 나타낼 수도 있다.
- 예: prod.istioinaction.io 와 api.istioinaction.io 가 모두 동일한 가상 IP로 해석되게 할 수 있다.
- 호스트네임에 대한 요청 모두 동일한 가상 IP로 흐르게 되고, 동일한 인그레스 리버스 프록시가 그 요청을 라우팅하게 된다.
- Host HTTP 헤더를 사용해 어느 요청이 어느 서비스 그룹으로 가야 하는지 기술할 수 있다
- 서로 다른 서비스 여러 개를 진입점 하나로 호스팅하는 것을 가상 호스팅 virtual hosting 이라고 한다.
- 특정 요청이 향하는 가상 호스트 그룹을 결정할 방법이 필요한데, HTTP/1.1 에서는 Host 헤더를 사용할 수 있고 HTTP/2에서는 :authority 헤더를 사용할 수 있다.
- TCP 커넥션에서는 TLS의 SNI server name indication 에 의존할 수 있다.
- 이스티오에서 보이는 에지 인그레스 기능이 서비스 트래픽을 클러스터 안으로 라우팅하는 데 가상 IP 라우팅과 가상 호스팅을 사용한다는 것이다.
HTTP/1.1, HTTP/2 헤더에 자세한 내용은 아래 블로그 참고 하세요
- host 헤더가 없는 이유(authority란?)
- HTTP 요청/응답 헤더 살펴보기
- HTTP/2 Request Smuggling 활용
2. Istio ingress gateways 이스티오 인그레스 게이트웨이
2.1 소개 (실습) Gateway(L4/L5), VirtualService(L7)
- 이스티오에서 네트워크 인그레스 포인트 역할을 하는 인그레스 게이트웨이
- 클러스터 외부에서 시작한 트래픽이 클러스터에 접근하는 것을 방어하고 제어한다. 로그 밸런싱과 가상 호스트 라우팅도 처리한다.
- 이스티오는 인그레스 게이트웨이로 단일 엔보이 프록시를 사용한다.
- 엔보이의 모든 기능은 인그레스 게이트웨이에서도 사용할 수 있다.
- 아래 그림은 이스티오의 인그레스 게이트웨이가 클러스터로 트래픽을 허용하면서 리버스 프록시 기능도 수행하는 것을 보여준다.
- 아래 그림은 컨트롤 플레인을 구성하는 요소와 컨트롤 플레인을 보조하는 추가 구성 요소의 목록을 보여준다.
- 실습-이스티오 서비스 프록시(엔보이 프록시)가 이스티오 인그레스 게이트웨이에서 실제로 작동 중인지 확인
- 아래 그림은 현재 실습의 흐름을 보여준다.
- 파드에서 컨테이너 1개 실행 : 별도의 어플리케이션 컨테이너 필요가 없다.
kubectl get pod -n istio-system -l app=istio-ingressgateway
- 프록시 상태 확인
docker exec -it myk8s-control-plane istioctl proxy-status
- 프록시 설정 확인
docker exec -it myk8s-control-plane istioctl proxy-config all deploy/istio-ingressgateway.istio-system
docker exec -it myk8s-control-plane istioctl proxy-config listener deploy/istio-ingressgateway.istio-system
- cluster, endpoint , log, sercret 설정 확인
# cluster
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/istio-ingressgateway.istio-system
# endpoint
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/istio-ingressgateway.istio-system
# log
docker exec -it myk8s-control-plane istioctl proxy-config log deploy/istio-ingressgateway.istio-system
# secret
docker exec -it myk8s-control-plane istioctl proxy-config secret deploy/istio-ingressgateway.istio-system
- istio-system 설정 yaml 형식으로 확인
kubectl get istiooperators -n istio-system -o yaml
- pilot-agent 프로세스가 envoy 를 부트스트랩
- 해당 정보를 통해 위에 그림 처럼 piot-agent -> envoy 구조를 확인 할수 있다.
kubectl exec -n istio-system deploy/istio-ingressgateway -- ps
kubectl exec -n istio-system deploy/istio-ingressgateway -- ps aux
- 프로세스 실행 유저 정보 확인
- root가 아니라 istio-proxy 이다
kubectl exec -n istio-system deploy/istio-ingressgateway -- whoami
kubectl exec -n istio-system deploy/istio-ingressgateway -- id
- 실행 결과, 이스티오 서비스 프록시에서 동작 중인 프로세스로 pilot-agent 와 envoy가 보여야 한다.
- pilot-agent 프로세스는 처음에 엔보이 프록시를 설정하고 부트스트랩한다.
- DNS 프록시도 구현한다.
- 인그레스 게이트웨이가 트래픽을 클러스터 내부로 허용하도록 설정하려면, 이스티오의 리소스인 Gateway 와 VirtualService 를 이해해야 한다, 두 리소스는 이스티오에서 트래픽의 흐름을 조절하는 데 핵심적인 역할을 한다.
2.2 Specifying Gateway resources 게이트웨이 리소스 지정하기 (실습)
- 이스티오에서 인그레스 게이트웨이를 설정하려면, Gateway 리소스를 사용해 개방하고 싶은 포트와 그 포트에서 허용할 가상 호스트를 지정한다.
- 아래 Gateway 리소스는 매우 간단해 80 포트에서 가상 호스트 webapp.istioinaction.io 를 향하는 트래픽을 허용하는 HTTP 포트를 개방한다.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: coolstore-gateway #(1) 게이트웨이 이름
spec:
selector:
istio: ingressgateway #(2) 어느 게이트웨이 구현체인가?
servers:
- port:
number: 80 #(3) 노출할 포트
name: http
protocol: HTTP
hosts:
- "webapp.istioinaction.io" #(4) 이 포트의 호스트
istio 동작을 잘 위해 하기위해 로그를 같이 보면서 실습을 하자
kubectl stern -n istio-system -l app=istiod
- Gateway 생성
- istioinaction 네임스페이스 리소스에 Gateway 생성한다.
kubectl -n istioinaction apply -f ch4/coolstore-gw.yaml
- 생성 확인
kubectl get gw,vs -n istioinaction
- 프록시 상태 확인
docker exec -it myk8s-control-plane istioctl proxy-status
- 리스너 정보 확인
docker exec -it myk8s-control-plane istioctl proxy-config listener deploy/istio-ingressgateway.istio-system
- 라우터 정보 확인
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/istio-ingressgateway.istio-system
- istio-ingressgateway Port 정보 확인
- Node Port (외부 포트)-> TargetPort (POD 포트) 의 순서로 진행된다.
kubectl get svc -n istio-system istio-ingressgateway -o jsonpath="{.spec.ports}" | jq
- HTTP 포트(80) 노출확인
- VirtualService 설정을 하지 않아서 리스너는 모든 것을 HTTP 404로 라우팅하는 기본 블랙홀 루트로 바인딩 한다.
- 기본 istio-ingresgateway 는 권한 있는 privileged 접근이 필요하지 않다. 시스템 포트(HTTP의 경우 80)을 리스닝하지 않기 때문이다.
- istio-ingresgateway 는 기본적으로 8080 포트를 리스닝한다. 그러나 실제 포트는 서비스일지 로드밸런서일지는 모르겠지만 게이트웨이를 노출하는 데 사용하는 포트다.
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/istio-ingressgateway.istio-system -o json
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/istio-ingressgateway.istio-system -o json --name http.8080
- 정리
- 특정 포트를 노출하고, 그 포트에서 특정 프로토콜을 예상하고, 그 포트/프로토콜 쌍에서 서빙할 특정 호스트를 정의했다.
- 앞에 실습에 확인 한것 처럼 트래픽을 서비스 메시내 특정 서비스로 가져올 방법이 필요하다
- VirtualService 리소스가 해당 역활을 한다.
2.3 Gateway routing with virtual services VirtualService로 게이트웨이 라우팅하기 (실습)
- 이스티오에서 VirtualService 리소스 클라이언트가 특정 서비스와 통신하는 방법을 정의 한다
- FQDN,
- 사용 가능한 서비스 버전,
- 기타 라우팅 속성(재시도, 요청 타임아웃 등)
- 2.2의 그림과 같이
- VirtualService(L7)는 URL,헤더 정보를 통해 특정 서비스에 라우팅을 한다.
- Gateway(L4-L6)는 외부트래픽을 진입점 이다.
쉽게 비유하면 우리가 일상 생활에서 백화점,놀이동산,문화센터를 놀러가면
입구에 도착해서 안내판을 확인한다.
즉, Gateway는 외부에서 들어오는 트래픽이 처음 도착하는 입구
VirtualService는 그 트래픽이 어느 서비스(전자 상가 층)로 갈지 결정하는 안내판
- 가상 호스트 webapp.istioinaction.io 로 향하는 트래픽을 서비스 메시 내에 배포된 서비스로 라우팅하는 VirtualService 예제
- coolstore-gateway 게이트웨이 정의를 통해 들어온 트래픽만 적용된다.
- 가상 호스트 webapp.istioinaction.io 로 향하는 트래픽에만 적용된다.
- 실행
kubectl apply -n istioinaction -f ch4/coolstore-vs.yaml
- Gateway VirtualServie 정보 확인
kubectl get gw,vs -n istioinaction
- 프록시 정보 확인 (상태,리스너,라우팅)
# 상태확인
docker exec -it myk8s-control-plane istioctl proxy-status
# 리스너
docker exec -it myk8s-control-plane istioctl proxy-config listener deploy/istio-ingressgateway.istio-system
# 라우팅
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/istio-ingressgateway.istio-system
- 이전과 달라진 http.8080 정보를 확인
- VirtualServie 서비스를 적용한 결과 virtuaHosts 많은 설정 정보들이 생성 되었다.
- 루트 출력은 다른 속성 및 정보를 포함할 수 있지만 이전과 비슷해야 한다.
- VirtualService를 정의하면 이스티오 게이트웨이에 엔보이 루트를 어떻게 생성하는지 확인 할 수 있다
- 도메인이 webapp.istioinaction.io 와 일치하는 트래픽을 서비스 메시 내 webapp 으로 라우팅하는 엔보이 루트다.
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/istio-ingressgateway.istio-system -o json --name http.8080
- cluster 에 webapp, catalog 정보 확인
- 실제 애플리케이션(서비스)를 배포 전으로 cluster 에 webapp, catalog 정보가 없다.
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/istio-ingressgateway.istio-system
- 서비스 배포
# catalog
kubectl apply -f services/catalog/kubernetes/catalog.yaml -n istioinaction
# webapp
kubectl apply -f services/webapp/kubernetes/webapp.yaml -n istioinaction
- Pod 정보 확인
# krew pulgin images 설치 후 사용
# kubectl krew install images
kubectl images -n istioinaction
- 파드에 컨테이너별 CPU/Mem Request/Limit 확인
kubectl resource-capacity -n istioinaction -c --pod-count -u
- 리스너, 클러스터 정보 확인
docker exec -it myk8s-control-plane istioctl proxy-config listener deploy/istio-ingressgateway.istio-system
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/istio-ingressgateway.istio-system | egrep 'TYPE|istioinaction'
- 엔드 포인트 정보 확인
- 해당 정보를 통해 알수 있는것은 istio-ingressgateway 에서 catalog/webapp 의 Service(ClusterIP)로 전달하는게 아니라, 바로 파드 IP인 Endpoint 로 전달한다.
- istio 를 사용하지 않았다면, Service(ClusterIP) 동작 처리를 위해서 Node에 iptable/conntrack 를 사용해야 한다.
- istio 사용 시에는 Node에 iptable/conntrack 를 사용하지 않아서, 이 부분에 대한 통신 라우팅 효율이 있다.
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/istio-ingressgateway.istio-system | egrep 'ENDPOINT|istioinaction'
- 각각의 서비스의 listener,routes,cluster,endpoint,secret 정보 확인
- 아래 출력 결과를 통해 현재 모든 istio-proxy 가 EDS로 K8S Service(Endpoint) 정보를 알 고 있다
# webapp
docker exec -it myk8s-control-plane istioctl proxy-config listener deploy/webapp.istioinaction
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/webapp.istioinaction
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/webapp.istioinaction
docker exec -it myk8s-control-plane istioctl proxy-config secret deploy/webapp.istioinaction
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/webapp.istioinaction | egrep 'ENDPOINT|istioinaction'
# catalog
docker exec -it myk8s-control-plane istioctl proxy-config listener deploy/catalog.istioinaction
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/catalog.istioinaction
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/catalog.istioinaction
docker exec -it myk8s-control-plane istioctl proxy-config secret deploy/catalog.istioinaction
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/catalog.istioinaction | egrep 'ENDPOINT|istioinaction'
- netshoot로 내부에서 catlog 접속 확인
kubectl exec -it netshoot -- curl -s http://catalog.istioinaction/items/1 | jq
- netshoot로 내부에서 webapp 접속 확인
- webapp은 다른 백엔드 서비스의 파사드 facade 역할을 한다.
- 파사드: 여러가지 마이크로 서비스를 단일 ApI로 노출 하는 방식, 내부적으로 요청을 적절한 서비스에 분산하거나 조합하여 처리한다.
kubectl exec -it netshoot -- curl -s http://webapp.istioinaction/api/catalog/items/1 | jq
- 서비스의 replicas 값 변경 : 해당 명령어 호출을 통해 설정 값을 변경 할수 있다.
- istio controlplane는 K8S Service 정보를 획득을 위해 Istio 가 K8S API에 요청하여 Service 등 정보를 주기적으로 Watch 하고, 변경 시 정보 요청하여 획득한다
kubectl scale deployment -n istioinaction webapp --replicas 2
kubectl scale deployment -n istioinaction catalog --replicas 2
- 인증서 정보 확인 : 해당 명령어로 확인을 할수 있다.
# webapp
istioctl proxy-config secret deploy/webapp.istioinaction -o json | jq '.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' -r | base64 -d | openssl x509 -noout -text
# gateway
istioctl proxy-config secret deploy/istio-ingressgateway.istio-system -o json | jq '.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' -r | base64 -d | openssl x509 -noout -text
# catalog
istioctl proxy-config secret deploy/catalog.istioinaction -o json | jq '.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' -r | base64 -d | openssl x509 -noout -text
- 외부 호출
- Host 헤더가 게이트웨이가 인식하는 호스트가 아니어서 실패한다.
curl http://localhost:30000/api/catalog -v
- Host 헤더 지정 후 호출
- http://localhost:30000/api/catalog 접속 하기 때문에 해당 정보로 찾을 수 없다 그래서 헤더에 주입해준다
curl -s http://localhost:30000/api/catalog -H "Host: webapp.istioinaction.io" | jq
2.4 Overall view of traffic flow 전체적인 트래픽 흐름 개요
- 이스티오 게이트웨이 리소스는 서비스 메시 클러스터의 에지에서 리스닝하고자 하는 포트, 프로토콜, 가상 호스트를 정의한다.
- VirtualService 리소스는 에지에서 허용된 트래픽이 가야 할 곳을 정의한다.
2.5 Istio ingress gateway vs. Kubernetes Ingress
- 이스티오는 쿠버네티스 인그레스 v1 리소스를 지원하지만, 쿠버네티스 인그레스 v1 사양에는 상당한 한계가 있다.
- 첫 번째 한계는 쿠버네티스 인그레스 v1 의 사양이 HTTP 워크로드에 맞춰져 매우 단순하다는 점이다.
- 실제로 인그레스 사양은 80포트와 443 포트만 인그레스 포인트로 간주한다.
- 이는 클러스터 운영자가 서비스 메시로 허용할 수 있는 트래픽 유형을 심각하게 제한한다.
- 예를 들어 카프카나 NATS.io 워크로드가 있다면, 이들 메시지 시스템에 TCP 커넥션을 직접 노출하고 싶을 수 있다. 쿠버네티스 인그레스는 이를 허용하지 않는다.
- 실제로 인그레스 사양은 80포트와 443 포트만 인그레스 포인트로 간주한다.
- 두 번째로, 쿠버네티스 인그레스 v1 리소스는 사양이 심각하게 부족하다는 점을 지적할 수 있다.
- 복잡한 트래픽 라우팅 규칙, 트래픽 분할, 트래픽 섀도잉 같은 것들을 지정하는 일반적인 방법이 없다.
- 이런 영역에서 사양이 부족한 까닭에 각 벤더는 인그레스 구현체(HAProxy, Nginx 등)에서 설정의 최적 구현법을 재창조해야했다.
- 마지막으로, 사양이 부족하다 보니 벤더 대부분의 설정이 디플로이먼트의 맞춤형 애노테이션으로 노출하는 방식을 택했다는 점을 꼽을 수 있다.
- 이 애노테이션은 벤더마다 상이하고 호환되지 않으므로, 이스티오가 이런 추세에 따랐다면 에지 게이트웨이로서 엔보이의 모든 기능을 반영하기 위해 애노테이션이 더 많이 필요했을 것이다.
- 결국 이스티오는 인그레스 패턴을 백지 상태에서 시작해 구축하기로 결정했고, 4계층(전송)과 5계층(세션) 속성을 7계층(애플리케이션) 라우팅 문제로부터 명확하게 분리해냈다.
- 이스티오 Gateway는 L4/L5 문제를 처리하고, VirtualService는 L7 문제를 처리한다.
INFO 쿠버네티스 Gateway API
- 21~22년 시점에는 쿠버네티스 커뮤니티는 인그레스 v1 API를 대체하고자 Gateway API를 열심히 준비하고 있다.
- 현재는 Istio Gateway 및 VirtualService 리소스와 다른다.
- Istio의 구현체와 리소스는 Gateway API 보다 먼저 등장했고, 여러 면에서 Gateway API에 영감을 줬다.
2.6 Istio ingress gateway vs. API gateways
- API 게이트웨이는 조직이 네트워크나 아키텍처 경계의 서비스를 사용하는 클라이언트에게 서비스 구현의 세부 사항을 추상화활 수 있게 한다
- 클라이언트는 잘 문서화된 API들을 호출하게 되고, 이 API들은 앞뒤 호환성을 지니면서 발전하며, 셀프 서비스와 기타 사용 메커니즘을 제공할 수 있다.
- 이를 위해 API 게이트웨이는 여러 보안 기술(OIDC, OAuth 2.0, LDAP)을 사용해 클라이언트를 식별할 수 있어야 하고, 메시지를 변형할 수 있어야 하며(SOAP → REST, gRPC → REST, 바디 및 헤더 텍스트 기반 변환 등), 비즈니스 수준으로 정교하게 속도를 제한할 수 있어야 하고, 자체 가입 기능이나 개발자 포털을 제공할 수 있어야 한다.
- 이스티오의 인그레스 게이트웨이는 이런 것들을 기본적으로는 제공하지 않는다.
- 메시 안팎에서 이런 역할을 수행하는 더욱 강력한 API 게이트웨이를 찾는다면, 엔보이 프록시를 기반으로 하는 Solo.io Gloo Edge 같은 것을 살펴볼만 한다.
3. Securing gateway traffic 게이트웨이 트래픽 보안
클러스터 외부(퍼블릭 인터넷 등)의 서비스를 클러스터 내부에서 실행 중인 서비스에 연결할 때, 인그레스 게이트웨이의 기본 기능 중 하나는 트래픽을 보호해 시스템의 신뢰 구축을 돕는 것이다.
트래픽 보호는 클라이언트가 통신하려는 서버의 진위를 가리는 것에서 시작할 수 있다. 자신이 그 서비스라고 주장하는 서비스가 정말 통신하려는 서비스가 맞는지 검증하는 것이다. 또한 누군가가 도청하는 일을 막고 싶으므로 트래픽을 암호화해야 한다.
이스티오의 게이트웨이 구현을 사용하면 들어오는 TLS/SSL 트래픽을 종료하고, 백엔드 서비스로 전달하고, TLS가 아닌 트래픽을 적절한 TLS 포트로 리다이렉트하고, mTLS를 구현할 수 있다.
3.1 HTTP traffic with TLS (실습)
- MITM 공격을 방지하고 서비스 메시로 들어오는 모든 트래픽을 암호화하기 위해 이스티오 게이트웨이에 TLS를 설정할 수 있다.
- 들어오는 트래픽 모두가 HTTPS로 제공되도록 하는 것이다.
- 예: TLS 설정을 적용하고 HTTP 요청(80) 301 리다이렉트로 HTTPS로 전환
- MITM 공격이란 클라이언트가 어떤 서비스에 연결하려고 하지만, 그 서비스가 아닌 사칭 서비스에 언결할 때를 말한다.
- 사칭 서비스는 통신에 접근할 수 있게 되며, 여기에는 민감 정보도 포함된다. TLS는 이 공격을 완화하는 데 도움을 준다.
- 수신 트래픽에 HTTPS를 활성화하려면 게이트웨이가 사용할 비공개 키와 인증서를 올바르게 지정해야 한다.
- 서버가 제시하는 인증서는 서버가 클라이언트에게 자신의 정체를 알리는 방법이다.
- 인증서란 기본적으로 서버의 공개 키이며, 신뢰할 수 있는 기관인 인증 기관 (CA, Certificate Authority)에서 서명한 것이다.
- 먼저 클라이언트에 CA 발급자의 인증서가 설치돼 있어야 한다.
- 이는 이 발급자가 신뢰할 수 있는 CA이며 발급자가 발급한 인증서 역시 신뢰할 수 있다는 의미다.
- CA 인증서가 설치돼 있으면, 클라이언트는 인증서가 신뢰할 수 있는 CA가 서명한 것인지 검증할 수 있다.
- 그런 다음, 클라이언트는 인증서 내 공개 키를 사용해 서버로 보내는 트래픽을 암호화 한다.
- 서버는 비밀 키로 트래픽을 복호화 할 수 있다.
앞 선 설명은 정확하지 않다.
TLS handshake 에는 더 정교한 프로토콜이 포함되는데, 최초 통신에는 공개/비공개 키(비대칭)를 조합하고,
TLS 세션에서 트래픽 암호화/복호화에 사용할 세션 키(대칭)을 생성한다.
- 인증서 키 생성 후 확인
- istio-ingressgateway 가 인증서와 키를 사용하도록 설정하려면 먼저 인증서/키를 쿠버네티스 시크릿으로 만들어야 한다.
# webapp-credential 시크릿 만들기
kubectl create -n istio-system secret tls webapp-credential \
--key ch4/certs/3_application/private/webapp.istioinaction.io.key.pem \
--cert ch4/certs/3_application/certs/webapp.istioinaction.io.cert.pem
# 확인 : krew view-secret
kubectl view-secret -n istio-system webapp-credential --all
- istio-system 네임스페이스에 시크릿을 만든다. istio v1.13.0 에서는 게이트웨이의 TLS에서 사용하는 시크릿은 이스티오 인그레스 게이트웨이와 동일한 네임스페이스에 있을 때만 가져올 수 있다.
- 운영 환경에서는 인그레스 게이트웨이를 istio-system과 분리해 자체 네임스페이스에서 실행해야 한다.
- 인증서 와 키 사용하도록 설정 파일
- Gateway 리소스에서 인그레스 게이트웨이의 443 포트를 열고, 이를 HTTPS로 지정한다.
- 게이트웨이 설정에 tls 부분을 추가해 TLS에 사용할 인증서와 키의 위치를 지정한다.
- 위치가 istio-ingressgateway 에 마운트한 위치와 동일하다는 것을 확인하자.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: coolstore-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80 #1 HTTP 트래픽 허용
name: http
protocol: HTTP
hosts:
- "webapp.istioinaction.io"
- port:
number: 443 #2 HTTPS 트래픽 허용
name: https
protocol: HTTPS
tls:
mode: SIMPLE #3 보안 연결
credentialName: webapp-credential #4 TLS 인증서가 들어 있는 쿠버네티스 시크릿 이름
hosts:
- "webapp.istioinaction.io"
- 설정 후 확인
# 설정
kubectl apply -f ch4/coolstore-gw-tls.yaml -n istioinaction
# 확인
docker exec -it myk8s-control-plane istioctl proxy-config secret deploy/istio-ingressgateway.istio-system
- 호출 테스트 1 - 실패
- 서버(istio-ingressgateway 파드)에서 제공하는 인증서는 기본 CA 인증서 체인을 사용해 확인할 수 없다는 의미다.
- 정상적인 동작을 위해 curl 클라이언트에 적절한 CA 인증서 체인을 전달해보자.
- 호출 실패 원인: 기본 인증서 경로에 인증서 없음. 사설인증서 이므로 사설CA 인증서(체인) 필요
- 호출 테스트 2 - 실패
- 호출 실패 원인: 인증실패. 서버인증서가 발급된(issued) 도메인 “webapp.istioinaction.io”로 호출하지 않음 localhost로 호출함
- 해결을 위해 hosts 파일에 명시 `echo "127.0.0.1 webapp.istioinaction.io" | sudo tee -a /etc/hosts`
curl -v -H "Host: webapp.istioinaction.io" https://localhost:30005/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem
- 호출 테스트 3 - 성공
curl -v https://webapp.istioinaction.io:30005/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem
- 종단 간 end-to-end 암호화
- 이스티오 게이트웨이를 향하는 트래픽을 암호화함으로써 보호한다.
- 이스티오 인그레스 게이트웨이는 TLS 커넥션을 종료하고, 트래픽을 서비스 메시 내에서 실행 중인 뒷단의 webapp 서비스로 보낸다.
- istio-ingressgateway 와 webapp 서비스 사이의 홉은 서비스의 ID를 사용해 암호화한다.
TIP
인증서 워크플로우를 외부 CA 또는 자체적인 내부 PKI와 통합하고 싶을 수 있다.
통합하는 데는 cert-manager 등을 사용할 수 있다
자세한 정보는 공식 문서 참고. https://cert-manager.io/docs/
3.2 HTTP redirect to HTTPS (실습)
- Gateway 설정 파일 수정
- 아래 설정파일은 모든 트래픽 항상 TLS를 쓰도록 강제로 쓰고, HTTP 트래픽을 강제로 리다이렉트 한다.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: coolstore-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "webapp.istioinaction.io"
tls:
httpsRedirect: true #아래 옵션으로 강제한다.
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: webapp-credential
hosts:
- "webapp.istioinaction.io"
- 적용 후 실행
- 이 리다이렉트는 클라이언트에게 API의 HTTPS 버전을 호출하라고 지시한다.
kubectl apply -f ch4/coolstore-gw-tls-redirect.yaml
curl -v http://webapp.istioinaction.io:30000/api/catalog
3.3 HTTP traffic with mutual TLS (실습)
- TLS
- 표준 TLS를 사용해 서버가 자신의 정체를 클라이언트에게 증명
- 단순 TLS 시나리오에서는 서버가 자신의 공개 인증서를 클라이언트에게 보냈고, 클라이언트는 서버의 인증서에 서명한 CA를 신뢰할 수 있음을 검증했다.
- mTLS
- 사용 이유
- 클러스터 외부의 트래픽을 받아들이기 전에 클라이언트가 누군지 검증하고 싶다면 어떻게 해야 할까?
- 클라이언트가 자신의 공개 인증서를 보내게 하고 서버가 인증서를 신뢰하는지 검증하게 하고 싶다.
- 인증서는 트래픽을 암호화하는 데 사용한다.
- 기본 istio-ingressgateway 가 mTLS 커넥션에 참여하도록 구성하려면, 클라이언트의 인증서를 검증하는 데 사용할 수 있도록 CA 인증서 집합을 제공해야 한다.
- 쿠버네티스 시크릿으로 istio-ingressgateway 에세 이 CA 인증서(더 구체적으로 인증서 체인)를 사용할 수 있게 해야 한다.
- 아래 그림은 mTLS 프로토콜에서 클라이언트와 서버 모두가 어떻게 서로의 인증서를 검증하는지, 즉 어떻게 서로 인증하는지 보여준다.
- 사용 이유
- CA 인증서 체인으로 istio-ingressgateway-ca-cert 시크릿을 구성 후 확인
# Secret 생성 : (적절한 CA 인증서 체인) 클라이언트 인증서
kubectl create -n istio-system secret \
generic webapp-credential-mtls --from-file=tls.key=\
ch4/certs/3_application/private/webapp.istioinaction.io.key.pem \
--from-file=tls.crt=\
ch4/certs/3_application/certs/webapp.istioinaction.io.cert.pem \
--from-file=ca.crt=\
ch4/certs/2_intermediate/certs/ca-chain.cert.pem
# 확인
kubectl view-secret -n istio-system webapp-credential-mtls --all
- Gateway 리소스 업데이트
- expected 프로토콜을 mTLS로 구성
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: coolstore-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "webapp.istioinaction.io"
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: MUTUAL # mTLS 설정
credentialName: webapp-credential-mtls # 신뢰할 수 있는 CA가 구성된 자격 증명
hosts:
- "webapp.istioinaction.io"
- 적용 후 확인
kubectl apply -f ch4/coolstore-gw-mtls.yaml -n istioinaction
docker exec -it myk8s-control-plane istioctl proxy-config secret deploy/istio-ingressgateway.istio-system
- 호출 테스트 1. 실패
- 실패 원인: 클라이언트 인증서 없음 - SSL 핸드섀이크가 성공하지 못하여 거부됨
curl -v https://webapp.istioinaction.io:30005/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem
- 호출 테스트 2 - 성공
- 클라이언트 인증서/키 추가
curl -v https://webapp.istioinaction.io:30005/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem \
--cert ch4/certs/4_client/certs/webapp.istioinaction.io.cert.pem \
--key ch4/certs/4_client/private/webapp.istioinaction.io.key.pem
- 이스티오 게이트웨이는 istio-proxy 를 시작하는 데 사용하는 istio-agent 프로세스에 내장된 SDS에서 인증서를 가져온다.
- SDS는 업데이트를 자동으로 전파해야 하는 동적 API이다. 서비스 프록시도 마찬가지다.
3.4 Serving multiple virtual hosts with TLS (실습)
- 이스티오의 인그레스 게이트웨이는 동일한 HTTPS 포트(443)에서 자체 인증서와 비밀 키가 있는 여러 가상 호스트를 서빙할 수 있다.
- 동일 포트 및 프로토콜에 여러 항목을 추가한다.
- 예를 들어 자체 인증서와 키 쌍이 있는 webapp.istioinaction.io 와 catalog.istioinaction.io 서비스를 둘 다 추가할 수 있다.
- 각 항목에는 서빙하는 가상 호스트용으로 사용하는 고유한 인증서와 키가 있다. 이를 위해 인증서와 키를 추
kubectl create -n istio-system secret tls catalog-credential \
--key ch4/certs2/3_application/private/catalog.istioinaction.io.key.pem \
--cert ch4/certs2/3_application/certs/catalog.istioinaction.io.cert.pem
# Gateway 설정 업데이트
kubectl apply -f ch4/coolstore-gw-multi-tls.yaml -n istioinaction
- Gateway 로 노출한 catalog 서비스용 VirtualService 리소스 생성
# catalog-vs.yaml 설정 파일 내용
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: catalog-vs-from-gw
spec:
hosts:
- "catalog.istioinaction.io"
gateways:
- coolstore-gateway
http:
- route:
- destination:
host: catalog
port:
number: 80
# 적용
kubectl apply -f ch4/catalog-vs.yaml -n istioinaction
- 동시 적용이 되는지 확인
- 이전 실습과 마찬가지로 노트북 Host 파일에 수정
- echo "127.0.0.1 catalog.istioinaction.io" | sudo tee -a /etc/hosts
- 이전 실습과 마찬가지로 노트북 Host 파일에 수정
# webapp
curl -v https://webapp.istioinaction.io:30005/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem
# catalog
curl -v https://catalog.istioinaction.io:30005/items \
--cacert ch4/certs2/2_intermediate/certs/ca-chain.cert.pem
- SNI 강력함
- 두 호출 모두 동일한 응답으로 성공했다. 그런데 발신자마다 어떤 인증서를 제시해야 하는지를 이스티오 인그레스가 어떻게 아는지가 궁금할 수 있다.
- 이 커넥션들이 열린 포트는 하나인데, 게이트웨이는 클라이언트가 접근하려는 서비스가 어느것이고 그 서비스에 해당하는 인증서가 어느 것인지를 알 수 있을까?
- 해답은 SNI(서버 이름 표시)라는 TLS 확장에 있다.
- 기본적으로 HTTPS 커넥션이 만들어지면 클라이언트는 먼저 TLS 핸드셰이크의 ClientHello 부분에서 어느 서비스에 접근해야 하는지부터 전달한다.
- 이스티오의 게이트웨이(엄밀히는 엔보이)가 TLS의 SNI를 구현하는 덕분에 올바른 인증서를 제시할 수 있고 올바른 서비스로 라우팅 할 수 있는 것이다.
- HTTPS 경우 TLS CliendHello 의 SNI의 Server Name 에서 주소를 확인 후 통제합니다.
- Squid v3.5 부터 SslPeekAndSplice 기능으로 TLS ClientHello 의 SNI 값(URL 주소) 기반 통제 가능
보안 업계에 유명한 격언이 “보안은 원래 귀찮고, 불편해야 제대로 된 거다.” 있다.
앞으로도 보안은 편리함보다 구조와 원칙에 집중해야 한다는 걸 잊지 말자.
4. TCP traffic
이스티오 게이트웨이는 HTTP/HTTPS 트래픽뿐 아니라 TCP로 접근하는 모든 트래픽을 처리할 수 있다.
예를 들어, 인그레스 게이트웨이로 데이터베이스(MongoDB 등)나 메시지 큐(카프카 등)를 노출할 수 있다.
이스티오가 트래픽을 단순 TCP로 다루면 재시도, 요청 수준 서킷 브레이킹, 복잡한 라우팅 등과 같은 유용한 기능을 사용할 수 없다.
이스티오가 어떤 프로토콜을 사용하는지 분간할 수 없기 때문이다. (MongoDB 처럼 이스티오-엔보이가 이해하는 프로토콜을 사용하는 것이 아닌 이상).
클러스터 외부의 클라이언트가 클러스터 내에서 실행 중인 서비스와 통신할 수 있도록 이스티오 게이트웨이에 TCP 트래픽을 노출하는 방법을 알아보자.
깃허브의 에코서비스 사용 - https://github.com/cjimti/go-echo
4.1 Exposing TCP ports on an Istio gateway (실습)
- TCP 서비스는 Telnet 같은 간단한 TCP 클라이언트로 접속해 명령어를 입력하면 그대로 되돌려준다.
- 설정 파일 확인
apiVersion: apps/v1
kind: Deployment
metadata:
name: tcp-echo-deployment
labels:
app: tcp-echo
system: example
spec:
replicas: 1
selector:
matchLabels:
app: tcp-echo
template:
metadata:
labels:
app: tcp-echo
system: example
spec:
containers:
- name: tcp-echo-container
image: cjimti/go-echo:latest # 해당 실습을 위해 go-echo 이미지를 사용한다.
imagePullPolicy: IfNotPresent
env:
- name: TCP_PORT
value: "2701"
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: SERVICE_ACCOUNT
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
ports:
- name: tcp-echo-port
containerPort: 2701
---
apiVersion: v1
kind: Service
metadata:
name: "tcp-echo-service"
labels:
app: tcp-echo
system: example
spec:
selector:
app: "tcp-echo"
ports:
- protocol: "TCP"
port: 2701
targetPort: 2701
- 적용 및 정보 확인
kubectl apply -f ch4/echo.yaml -n istioinaction
kubectl get pod -n istioinaction
- tcp 서빙 포트 추가
- 터미널 편집기를 이용해서 수정을 한다. 현재 사용하고있는 툴 명령어에 맞게 수정하자
KUBE_EDITOR="lvim" kubectl edit svc istio-ingressgateway -n istio-system
- 확인
kubectl get svc istio-ingressgateway -n istio-system -o jsonpath='{.spec.ports[?(@.name=="tcp")]}'
- 게이트웨이 생성 후 확인
# gateway-tcp 설정 파일 내용
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: echo-tcp-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 31400
name: tcp-echo
protocol: TCP
hosts:
- "*"
kubectl apply -f ch4/gateway-tcp.yaml -n istioinaction
kubectl get gw -n istioinaction
- 에코 서비스로 라우팅 위해 VirtualService 리소스 생성 후 확인
# echo-vs 설정 파일 내용
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: tcp-echo-vs-from-gw
spec:
hosts:
- "*"
gateways:
- echo-tcp-gateway
tcp:
- match:
- port: 31400
route:
- destination:
host: tcp-echo-service
port:
number: 2701
kubectl apply -f ch4/echo-vs.yaml -n istioinaction
kubectl get vs -n istioinaction
- 테스트
- 테스트를 위해 telnet 필요하다 없으면 설치 `brew install telnet`
telnet localhost 30006
4.2 Traffic routing with SNI passthrough (실습)
- 목표
- 두 기능의 조합. 즉 이스티오 인그레스 게이트웨이에서 트래픽을 종료하지 않고 SNI 호스트네임에 따라 TCP 트래픽을 라우팅하는 방법을 다룬다.
- 게이트웨이가 하는 일은 SNI 헤더를 살펴보고 트래픽을 특정 백엔드로 라우팅하는 것 뿐이다. TLS 커넥션 종료는 그 후 백엔드에서 처리한다.
- 커넥션은 게이트웨이를 ‘통과 passthrough’ 하고, 처리는 게이트웨이가 아닌 실제 서비스가 담당하게 된다.
- 이런 방식은 서비스 메시에 참여할 수 있는 애플리케이션의 범위를 휠씬 넓혀준다.
- 데이터베이스, 메시지 큐, 캐시 등과 같은 TLS 상의 TCP 서비스는 물론, HTTPS/TLS 트래픽을 직접 처리하고 종료할 것이라고 예상되는 레거시 애플리케이션까지도 포함될 수 있다.
- Gateway 설정파일 확인
- 애플리케이션에서 TLS를 종료하도록 설정한다. 즉, 인그레스 게이트웨이는 커넥션에 아무것도 하지 않아도 된다.
- 앞 절에서 했던 것처럼 게이트웨이에 인증서를 설정할 필요가 없다.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: sni-passthrough-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 31400 #1 HTTP 포트가 아닌 특정 포트 열기
name: tcp-sni
protocol: TLS
hosts:
- "simple-sni-1.istioinaction.io" #2 이 호스트를 포트와 연결
tls:
mode: PASSTHROUGH #3 통과 트래픽으로 처리
- TLS를 종료하는 예제 애플레케이션 배포
- TLS 인증을 직접 처리하는 앱 배포. (gw는 route 만 처리, pass through )
- 기존 Gateway 명세(echo-tcp-gateway) 제거 : istio-ingressgateway의 동일한 port (31400, TCP)를 사용하므로 제거함
# TLS 인증을 직접 처리하는 앱 배포.
cat ch4/sni/simple-tls-service-1.yaml
kubectl apply -f ch4/sni/simple-tls-service-1.yaml -n istioinaction
kubectl get pod -n istioinaction
# 기존 Gateway 명세(echo-tcp-gateway) 제거
kubectl delete gateway echo-tcp-gateway -n istioinaction
# 신규 Gateway 설정
kubectl apply -f ch4/sni/passthrough-sni-gateway.yaml -n istioinaction
kubectl get gw -n istioinaction
- VirtualService 리소스 라우팅 규칙 지정
# passthrough-sni-vs-1 설정 파일 내용
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: simple-sni-1-vs
spec:
hosts:
- "simple-sni-1.istioinaction.io"
gateways:
- sni-passthrough-gateway
tls:
- match: #1 특정 포트와 호스트의 비교 부분
- port: 31400
sniHosts:
- simple-sni-1.istioinaction.io
route:
- destination: #2 트래픽이 일치하는 경우 라우팅 목적지
host: simple-tls-service-1
port:
number: 80 #3 서비스 포트로 라우팅
kubectl apply -f ch4/sni/passthrough-sni-vs-1.yaml -n istioinaction
kubectl get vs -n istioinaction
- 호출 테스트 1
- curl 호출은 이스티오 인그레스 게이트웨이로 갔다가, 종료 없이 예제 서비스 simple-tls-service-1 에 도달한다.
echo "127.0.0.1 simple-sni-1.istioinaction.io" | sudo tee -a /etc/hosts
curl https://simple-sni-1.istioinaction.io:30006/ \
--cacert ch4/sni/simple-sni-1/2_intermediate/certs/ca-chain.cert.pem
- 라우팅을 더 명확하게 하기 위해 인증서가 다르고 SNI 호스트에 기반해 라우팅을 하는 두 번째 서비스를 배포
# 두 번째 서비스 배포
kubectl apply -f ch4/sni/simple-tls-service-2.yaml -n istioinaction
# gateway 설정 업데이트
kubectl apply -f ch4/sni/passthrough-sni-gateway-both.yaml -n istioinaction
# VirtualService 설정
kubectl apply -f ch4/sni/passthrough-sni-vs-2.yaml -n istioinaction
- 호출 테스트 2
- simple-tls-sni-2 서비스가 서빙했음을 body 필드의 응답이 어떻게 알려주는지 주목하자.
echo "127.0.0.1 simple-sni-2.istioinaction.io" | sudo tee -a /etc/hosts
curl https://simple-sni-2.istioinaction.io:30006 \
--cacert ch4/sni/simple-sni-2/2_intermediate/certs/ca-chain.cert.pem
5. Operational tips 운영 팁
5.1 Split gateway responsibilities 게이트웨이 책임 나누기 (실습)
- 인그레스 게이트웨이를 여럿(다른 진입점) 둘 수 있다.
- 다른 진입점을 배포해 트래픽을 나누고 다양한 서비스 간 트래픽 경로를 격리하고 싶을 수도 있다.
- 어떤 서비스는 성능에 더 민감하거나, 고가용성이 더 필요하거나, 컴플라이언스를 이유로 격리돼야 할 수도 있다.
- 어떤 떄는 다른 팀에 영향을 주지 않도록 각 팀이 각자의 게이트웨이 및 설정을 소유하게 하고 싶을 수도 있다
- 새 커스텀 게이트웨이 정의 예시
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: my-user-gateway-install
namespace: istioinaction
spec:
profile: empty
values:
gateways:
istio-ingressgateway:
autoscaleEnabled: false
components:
ingressGateways:
- name: istio-ingressgateway
enabled: false
- name: my-user-gateway
namespace: istioinaction
enabled: true
label:
istio: my-user-gateway
k8s:
service:
ports:
- name: tcp # my-user-gateway 에서 사용할 포트 설정
port: 30007
targetPort: 31400
- 컨틀롤 플레인 직접 접속해 설치
docker exec -it myk8s-control-plane bash
# istioinaction 네임스페이스에 Ingress gateway 설치
cat <<EOF > my-user-gateway-edited.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: my-user-gateway-install
namespace: istioinaction
spec:
profile: empty
values:
gateways:
istio-ingressgateway:
autoscaleEnabled: false
components:
ingressGateways:
- name: istio-ingressgateway
enabled: false
- name: my-user-gateway
namespace: istioinaction
enabled: true
label:
istio: my-user-gateway
k8s:
service:
ports:
- name: tcp # my-user-gateway 에서 사용할 포트 설정
port: 31400
targetPort: 31400
nodePort: 30007 # 외부 접속을 위해 NodePort Number 직접 설정
EOF
# istioctl manifest generate -n istioinaction -f my-user-gateway-edited.yaml
istioctl install -y -n istioinaction -f my-user-gateway-edited.yaml
- IstioOperator 확인
# IstioOperator 확인
kubectl get IstioOperator -A
kubectl get deploy my-user-gateway -n istioinaction
# 포트 확인
kubectl get svc my-user-gateway -n istioinaction -o yaml
- my-user-gateway를 경유하여 TCP 통신
# Gateway
cat <<EOF | kubectl apply -n istioinaction -f -
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: echo-tcp-gateway
spec:
selector:
istio: my-user-gateway # New gateway
servers:
- port:
number: 31400
name: tcp-echo
protocol: TCP
hosts:
- "*"
EOF
# VirtualService 명세
kubectl apply -f ch4/echo-vs.yaml -n istioinaction
# 앱 배포
kubectl apply -f ch4/echo.yaml -n istioinaction
# 호출 테스트 : NodePort 30007로 접속 테스트
telnet localhost 30007
5.2 Gateway injection 게이트웨이 주입 (실습)
- 사용자에게 IstioOperator 리소스(기존 이스티오 설치를 변경할 수 있는)에 대한 전체 접근 권한을 부여하지 않고도 자체 게이트웨이를 만들 수 있게 허용하는 방법은 게이트웨이 주입 gateway injection 을 사용하는 것이다.
- 게이트웨이 주입을 사용하며, 미완성 subbed-out 게이트웨이 디플로이먼트를 배포하고 이스티오가 나머지를 채우는 방식이 된다.
- 사이드카 주입이 이뤄지는 방식과 비슷하다.
- 이런 방식으로, 팀에서 미완성 게이트웨이 Deployment 리소스를 주고 이스티오가 나머지를 자동 설정하게 할 수 있다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-user-gateway-injected
namespace: istioinaction
spec:
selector:
matchLabels:
ingress: my-user-gateway-injected
template:
metadata:
annotations:
sidecar.istio.io/inject: "true" #1 주입 활성화
inject.istio.io/templates: gateway #2 gateweay 템플릿
labels:
ingress: my-user-gateway-injected
spec:
containers:
- name: istio-proxy #3 반드시 이 이름이어야 한다
image: auto #4 미완성 이미지
...
- 적용
kubectl apply -f ch4/my-user-gw-injection.yaml
kubectl get deploy,svc,ep my-user-gateway-injected -n istioinaction
5.3 Ingress gateway access logs 인그레스 게이트웨이 액세스 로그 (실습)
- 프록시에서 일반적인 기능은 처리하는 모든 요청을 기록하는 것이다. 이 액세스 로그는 문제 해결에 유용한다.
- 이스티오의 프록시(엔보이)도 액세스 로그를 만들 수 있다.
- 데모 설치 프로필에서는 인그레스 게이트웨이와 서비스 프록시가 액세스 로그를 표준 출력 스트림에 출력하도록 설정된다.
- 액세스 로그를 보려면 컨테이너 로그를 출력하기만 하면 된다.
- 인그레스 게이트웨이의 액세스 로그를 출력한다. 따라서 앞선 예제들에서 만들어낸 트래픽들의 기록을 볼 수 있다.
kubectl logs -f deploy/istio-ingressgateway -n istio-system
- 기본 프로필로 로그 실행
- 기본 프로필을 사용한 운영 환경 이스티오에서는 액세스 로깅이 비활성화 되어 있다.
# 테스트를 위해 반복 호출
watch -d -n 1 curl -s -v https://webapp.istioinaction.io:30005/api/catalog --cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem
# 초기 부팅 로그 이외에 별다른 로그 출력이 없음
kubectl stern -n istioinaction -l app=webapp -c istio-proxy
- 표준 출력 스트림으로 출력하도록 accessLogFile 속성을 변경 하면 사용이 가능하다.
# 컨틀로 플레인에 접속
docker exec -it myk8s-control-plane bash
# 표준 출력 스트림으로 출력하도록 accessLogFile 속성을 변경
istioctl install --set meshConfig.accessLogFile=/dev/stdout # y를 입력을 해서 적용하자
exit
- 액세스 로그는 기본적으로 꺼져 있는데, 운영 환경 클러스터에서 수백 또는 수천 개의 워크로드가 있고 각 워크로드가 많은 트래픽을 처리한다는 점을 고려하면 합리적이다.
- 또한 각 요청은 한 서비스에서 다른 서비스로 여러 홉을 이동하기 때문에 생성되는 액세스 로그량은 어떤 로깅 시스템에든 부담을 줄 수 있다.
- 더 나은 접근 방식은 관심 있는 워크로드에 대해서만 액세스 로그를 켜는 것이며, 이는 텔레메트리 API를 사용해 가능하다.
- 예를 들어 인그레스 게이트웨이 워크로드의 액세스 로그만 표시하려면 다음과 같은 텔레메트리 설정을 사용할 수 있다.
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: ingress-gateway
namespace: istio-system
spec:
selector:
matchLabels:
app: istio-ingressgateway #1 레이블과 일치하는 파드는 텔레메트리 설정을 가져온다
accessLogging:
- providers:
- name: envoy #2 액세스 로그를 위한 프로바이더 설정
disabled: false #3 disable 를 false 로 설정해 활성화한다
- 토스 사례 : istio-proxy 에서 gRPC로 직접 Acess log collector 로 수집(Go로 직접 개발) → Kafka → Logstash → ES
5.4 Reducing gateway configuration 게이트웨이 설정 줄이기
- 기본적으로, 이스티오는 모든 프록시가 메시 내의 모든 서비스를 알도록 구성한다. 메시에 서비스가 많다면 데이터 플레인 프록시의 설정이 매우 커질 수 있다. 그리고 설정이 크면 리소스 증폭, 성능 문제, 확장성 문제로 이어질 수 있다.
- 이 문제를 해결하기 위해 데이터 플레인과 컨트롤 플레인 모두에게 설정을 최적화할 수 있다.
- Sidecar 리소스를 사용해 이 설정을 줄이는 방법이 있다.
- Sidecar 리소스 설정의 한계
- Sidecar 리소스는 게이트웨이에는 적용되지 않는다.
- 새 게이트웨이(인그레스 게이트웨이 등)를 배포하면 프록시에는 메시 내 라우팅할 수 있는 모든 서비스가 설정된다.
- 이렇게 하면 설정이 아주 커져 게이트웨이에 부담이 될 수 있다.
- 요령은 프록시에서 필요 이상의 설정은 제거하고 게이트웨이 관련 설정만 포함되도록 하는 것이다.
- 최근까지 이 기능은 기본적으로 꺼져 있었는데, 최신 버전에서는 활성화 여부를 확인 할 수 있다.
- 어느 버전이든 다음 설정으로 게이트웨이의 설정 잘라내기를 명시적으로 활성화할 수 있다.
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: control-plane
spec:
profile: minimal
components:
pilot:
k8s:
env:
- name: PILOT_FILTER_GATEWAY_CLUSTER_CONFIG
value: "true"
meshConfig:
defaultConfig:
proxyMetadata:
ISTIO_META_DNS_CAPTURE: "true"
enablePrometheusMerge: true
#
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/my-user-gateway.istioinaction
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
BlackHoleCluster - - - STATIC
agent - - - STATIC
catalog.istioinaction.svc.cluster.local 80 - outbound EDS
...
# 현재 37개 cluster 정보
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/my-user-gateway.istioinaction | wc -l
37
# 아래 추가
KUBE_EDITOR="nano" kubectl edit IstioOperator -n istioinaction installed-state-my-user-gateway-install
...
pilot:
enabled: false
k8s:
env:
- name: PILOT_FILTER_GATEWAY_CLUSTER_CONFIG
value: "true"
...
# 동일... 해당 gw pod 삭제 후 재시작 되어도 동일.. 다른 설정 방법이 있나?... kubectl edit 대신 IstioOperator 로 설정해야할지도..
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/my-user-gateway.istioinaction | wc -l
37
- 이 설정의 핵심은 PILOT_FILTER_GATEWAY_CLUSTER_CONFIG 기능 플래그이다. - 공식문서
- If enabled, Pilot will send only clusters that referenced in gateway virtual services attached to gateway
- 이 플래그는 게이트웨이 프록시 설정 내에 있는 클러스터를 해당 게이트웨이에 적용한 VirtualService 에서 실제로 참조하는 클러스터로만 좁힌다.
정리
옵저버빌리티 기능이 풍부하다, 대신 리소스가 너무 많다.
최적화를 위해 리소스 절감을 위해 비활성화 또는 경량화하는 것도 고려 해보야 합니다.
정리
- 인그레스 게이트웨이는 서비스 메시에 들어오는 트래픽을 세밀하게 제어합니다.
- Ingress gateways provide fine-grained control over what traffic enters our service mesh.
- 게이트웨이 리소스를 사용하면 메시 내로 허용하는 트래픽 종류를 호스트별로 설정할 수 있다.
- Using the Gateway resource, we can configure the type of traffic admitted into the mesh for a specific host.
- 메시 내의 다른 서비스와 마찬가지로, 트래픽을 라우팅하기 위해 VirtualService 리소스를 사용합니다.
- Just as with any service in the mesh, it uses VirtualService resources to route the traffic.
- TLS 모드는 호스트마다 다음 모드 중 하나로 구성할 수 있습니다. TLS mode is configurable per host with one of the following modes:
- Encrypt and prevent man-in-the-middle attacks with the SIMPLE TLS mode.
- Mutually authenticate both server and client with the MUTUAL TLS mode.
- Admit and reverse proxy encrypted traffic using the SNI header with the PASSTHROUGH TLS mode.
- 현재 지원되지 않는 L7 프로토콜의 경우 Istio에서 순수 TCP 트래픽이 지원됩니다. 그러나 재시도, 복잡한 라우팅 등 일반 TCP에서는 많은 기능을 사용할 수 없습니다.
- Plain TCP traffic is supported in Istio for L7 protocols that are currently not supported. However, many features are not possible with plain TCP, such as retries, complex routing, and so on.
- 게이트웨이 주입을 사용하여 팀이 자체 게이트웨이를 관리할 수 있도록 할 수 있습니다.
- We can enable teams to manage their own gateways by using gateway injection.
실습 정리
- kind delete cluster --name myk8s
- /etc/hosts 파일에 추가했던 도메인 제거
'Istio Hands-on Study [1기]' 카테고리의 다른 글
[3주차]Traffic control,Resilience - Traffic control 개념정리 및 실습 (0) | 2025.04.26 |
---|---|
[3주차]Traffic control, Resilience - Resilience 개념정리 및 실습 (0) | 2025.04.26 |
[2주차] Envoy,Istio Gateway - Envoy Proxy 개념 정리 및 실습 (0) | 2025.04.18 |
[1주차]Istio 첫걸음 - Istio 실습 환경 구성 및 체험 (0) | 2025.04.11 |
[1주차]Istio 소개 첫 걸음 - Istio 정리 (0) | 2025.04.11 |
📚 목차 보기