Istio Ingress Gateway 란?
Istio에서 Ingress Gateway는 외부에서 들어오는 트래픽을 Mesh 내부로 유입시키는 진입점 역할을 한다.
기존 Kubernetes의 Ingress와 비슷한 개념이지만, 더 세밀한 제어와 L7 기반의 트래픽 정책을 지원한다.
Istio Ingress Gateway의 동작과 기능에 대해 알아보도록 하자.
Istio API vs Kubernetes Gateway API
Kubernetes도 최근 Gateway API를 정식 채택하면서, “Gateway”라는 용어가 Kubernetes와 Istio 양쪽에서 다르게 사용되며 혼동을 줄 수 있다. 게다가 게이트웨이의 구현체에 따라 구성 방식이 달라지기 때문에, 어떤 방식으로 정의하고 구성하느냐에 따라 사용 리소스와 동작 방식도 달라진다.
이번 실습에서는 Istio의 Ingress Gateway(istio-ingressgateway)의 내용을 다루기 때문에, Istio의 Gateway를 사용한다.
Istio는 현재 다음 두 가지 방식 모두를 지원하고 있다.
Istio Ingress Gateway로 외부 트래픽 라우팅하기
Istio Ingress Gateway를 통해서 외부 트래픽을 라우팅해보자.
Gateway 설정
- Istio Ingress Gateway는 Gateway 리소스를 통해 수신 포트 및 호스트를 정의한다.
- 기본 게이트웨트는 80 포트에서
webapp.istioinaction.io
를 향하는 트래픽을 허용하는 HTTP 포트를 개방한다.
# gateway 리소스 생성
kubectl -n istioinaction apply -f ch4/coolstore-gw.yaml
VirtualService 설정
- 트래픽이 게이트웨이로 들어오면, 그 트래픽을 서비스 메시 내 특정 서비스로 가져온다.
- 클라이언트가 특정 서비스와 통신 하는 방법 정의(FQDN, 서비스 버전, 라우팅속성: 재시도, 요청타임아웃 등)
VirtualService 리스스 생성
kubectl apply -n istioinaction -f ch4/coolstore-vs.yaml
리소스 확인
생성한 Gateway와 VirtualService를 확인한다.
# 확인
kubectl get gw,vs -n istioinaction
NAME AGE
gateway.networking.istio.io/coolstore-gateway 104s
NAME GATEWAYS HOSTS AGE
virtualservice.networking.istio.io/webapp-vs-from-gw ["coolstore-gateway"] ["webapp.istioinaction.io"] 10s
# 배포 전
docker exec -it myk8s-control-plane istioctl proxy-status
NAME CLUSTER CDS LDS EDS RDS ECDS ISTIOD VERSION
istio-ingressgateway-996bc6bb6-ffqvs.istio-system Kubernetes SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-7df6ffc78d-7p4ls 1.17.8
샘플 애플리케이션 배포
저번 예제에서 다뤘던 샘플 애플리케이션을 배포하고, 해당 서비스를 라우팅한다.
cd /istio-in-action/book-source-code-master
kubectl apply -f services/catalog/kubernetes/catalog.yaml -n istioinaction
kubectl apply -f services/webapp/kubernetes/webapp.yaml -n istioinaction
# 파드 확인
kubectl get pod -n istioinaction
NAME READY STATUS RESTARTS AGE
catalog-6cf4b97d-xpswv 2/2 Running 0 3m33s
webapp-7685bcb84-z7xjg 2/2 Running 0 3m33s
프록시 상태 확인
istio-proxy의 엔드포인트 정보를 확인해보면 샘플 애플리케이션을 동기화함을 확인할 수 있다.
docker exec -it myk8s-control-plane istioctl proxy-status
NAME CLUSTER CDS LDS EDS RDS ECDS ISTIOD VERSION
catalog-6cf4b97d-xpswv.istioinaction Kubernetes SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-7df6ffc78d-7p4ls 1.17.8
istio-ingressgateway-996bc6bb6-ffqvs.istio-system Kubernetes SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-7df6ffc78d-7p4ls 1.17.8
webapp-7685bcb84-z7xjg.istioinaction Kubernetes SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-7df6ffc78d-7p4ls 1.17.8
# 모든 istio-proxy 가 EDS로 해당 K8S Service의 Endpoint 목록 정보 동기화되어 알고 있음을 확인
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/catalog.istioinaction | egrep 'ENDPOINT|istioinaction'
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.10.0.12:3000 HEALTHY OK outbound|80||catalog.istioinaction.svc.cluster.local
10.10.0.13:8080 HEALTHY OK outbound|80||webapp.istioinaction.svc.cluster.local
istiod의 설정이 반영되는 로그를 확인할 수 있다.
외부 트래픽 테스트
게이트웨이에서 설정한 도메인 호스트가 아니기 때문에, 404 에러를 벹는다.
외부(?)에서 호출 시도 : Host 헤더가 게이트웨이가 인식하는 호스트가 아니다
curl http://localhost:30000/api/catalog -v
< HTTP/1.1 404 Not Found
...
등록한 도메인, 호스트 헤더를 추가하여 다시 요청하면
curl -s http://localhost:30000/api/catalog -H "Host: webapp.istioinaction.io" | jq
[
{
"id": 1,
"color": "amber",
"department": "Eyewear",
"name": "Elinor Glasses",
"price": "282.00"
}
...
🤔 Istio IngressGateway 외부 노출 방식
Istio Ingress Gateway는 기본적으로 LoadBalancer 타입 서비스로 배포되지만, 하지만, 클러스터 환경이나 네트워크 요구 사항에 따라 다음과 같은 방식으로 외부에 노출할 수 있다.
• NodePort 방식
클러스터 노드의 특정 포트를 열어 Ingress Gateway가 외부에서 접근 가능하도록 설정
• hostNetwork 방식 (예: Toss 사례)
파드가 노드의 네트워크 인터페이스를 직접 사용하는 방식
→ 이 경우 externalTrafficPolicy: Local, podAffinity 등의 설정이 중요합니다.
Securing gateway traffic : 게이트웨이 트래픽 보안
HTTP traffic with TLS
Istio Ingress Gateway + TLS 설정으로 HTTPS 트래픽 보호하기
Istio Gatway를 통해 외부로부터 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
Multiple sub keys found. Specify another argument, one of:
-> tls.crt
-> tls.key
# 인증서 파일 확인
openssl x509 -in ch4/certs/3_application/certs/webapp.istioinaction.io.cert.pem -noout -text
Gateway 리소스에 TLS 설정 추가
- Gateway 리소스에서 인그레스 게이트웨이의 443 포트를 열고, 이를 HTTPS로 지정한다.
- 또한 게이트웨이 설정에 tls 부분을 추가해 TLS에 사용할 인증서와 키의 위치를 지정한다.
# Gateway 배포
kubectl apply -f ch4/coolstore-gw-tls.yaml -n istioinaction
Istiod 로그를 확인해보면 SDS(보안관련설정)가 적용되었음을 확인할 수 있다.
TLS 통신 테스트 및 SNI 문제 해결 과정
❌ Step 1: 인증서 없이 호출 → 실패
• 실패 원인: TLS 인증서 검증 실패
• 기본 CA 체인으로 사설 인증서 검증 불가
# 호출 테스트 1
curl -v -H "Host: webapp.istioinaction.io" https://localhost:30005/api/catalog
...
* CAfile: /etc/ssl/cert.pem
* CApath: none
* LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to localhost:30005
* Closing connection
curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to localhost:30005
...
❌ Step 2: CA 체인 전달해도 실패
• 실패 원인: SNI(Server Name Indication) 불일치
• URL은 localhost인데, 인증서는 webapp.istioinaction.io 기준으로 발급되어 있음
📌 SNI란?
TLS 연결에서 클라이언트가 서버와 통신할 정확한 도메인을 ServerHello 전에 명시하는 확장 필드.
즉, Host 헤더가 아니라 curl https://[도메인]에 사용된 도메인 주소 자체가 중요함!
암호화된 통신(https)에서 SNI 필드를 통해 클라이언트의 도메인은 확인하여, 효율적인 통신이 가능
# 호출 테스트 2
curl -v -H "Host: webapp.istioinaction.io" https://localhost:30005/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem
...
* CAfile: ch4/certs/2_intermediate/certs/ca-chain.cert.pem
* CApath: none
* LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to localhost:30005
* Closing connection
curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to localhost:30005
...
✅ Step 3: /etc/hosts에 도메인 추가 후 성공
• 성공적으로 HTTPS 요청 처리됨
• Istio Gateway는 SNI 정보 기반으로 인증서 선택 및 트래픽 수신 완료
# SNI 해결용 로컬 도메인 매핑 추가
echo "127.0.0.1 webapp.istioinaction.io" | sudo tee -a /etc/hosts
# 올바른 SNI + CA 인증서 포함 요청
curl -v https://webapp.istioinaction.io:30005/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem
HTTP redirect to HTTPS
Istio Gateway에 httpsRedirect 옵션을 설정하면, 모든 HTTP 요청을 안전하게 HTTPS로 강제 리디렉션할 수 있다.
Gateway 설정 변경
• 기존 HTTP 80 포트의 Gateway 설정에 tls.redirect: true 속성 추가
• 클라이언트가 HTTP로 접속하면, 301 Moved Permanently 응답과 함께 HTTPS 주소로 유도됨
kubectl apply -f ch4/coolstore-gw-tls-redirect.yaml
통신 테스트
• HTTP 요청은 허용되지 않으며, 브라우저/클라이언트는 자동으로 HTTPS 주소로 이동
• 별도의 애플리케이션 레벨 리디렉션 없이, Envoy 레벨에서 처리
HTTP traffic with mutual TLS(mTLS)
Istio Gateway에 mTLS(MUTUAL 모드)를 적용하면, 서버뿐만 아니라 클라이언트의 신원도 TLS 인증서로 검증할 수 있다.
mTLS는 서버뿐만 아니라 클라이언트의 신원까지 검증하는 TLS 방식이다. 서비스 보안이 중요한 금융권이나,공공기관에서는 내부 통신에서 필수적으로 요구되는데, Istio를 사용하면 손쉽게 구현이 가능하다.
클라이언트 인증서 생성 및 등록
ca.crt, tls.crt, tls.key 파일을 쿠버네티스 시크릿으로 등록한다. → 이 시크릿은 Gateway에서 mTLS 설정 시 사용됨.
# 생성
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 get secret -n istio-system webapp-credential-mtls
NAME TYPE DATA AGE
webapp-credential-mtls Opaque 3 39s
Gateway에 mTLS 설정 추가
SIMPLE 대신 MUTUAL 모드를 사용
# 게이트웨이 설정 배포
kubectl apply -f ch4/coolstore-gw-mtls.yaml -n istioinaction
SDS(Secret Discovery Service)를 통해 인증서가 자동 마운트됨
통신 테스트
❌ 실패 테스트: 클라이언트 인증서 없이 요청
• 클라이언트 인증서가 없어 TLS 핸드셰이크 실패
curl -v https://webapp.istioinaction.io:30005/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem
...
* Request completely sent off
* LibreSSL SSL_read: LibreSSL/3.3.6: error:1404C45C:SSL routines:ST_OK:reason(1116), errno 0
* Failed receiving HTTP2 data: 56(Failure when receiving data from the peer)
* Connection #0 to host webapp.istioinaction.io left intact
curl: (56) LibreSSL SSL_read: LibreSSL/3.3.6: error:1404C45C:SSL routines:ST_OK:reason(1116), errno 0
✅ 성공 테스트: 클라이언트 인증서/키 포함
• TLS 핸드셰이크 성공
• 클라이언트 인증 완료 후, 정상적으로 응답 수신
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
....
* Request completely sent off
< HTTP/2 200
< content-length: 357
< content-type: application/json; charset=utf-8
< date: Thu, 17 Apr 2025 13:29:50 GMT
< x-envoy-upstream-service-time: 20
< server: istio-envoy
<
* Connection #0 to host webapp.istioinaction.io left intact
[{"id":1,"color":"amber","department":"Eyewear","name":"Elinor Glasses","price":"282.00"},{"id":2,"color":"cyan","department":"Clothing","name":"Atlas Shirt","price":"127.00"},{"id":3,"color":"teal","department":"Clothing","name":"Small Metal Shoes","price":"232.00"},{"id":4,"color":"red","department":"Watches","name":"Red Dragon Watch","price":"232.00"}]%
Serving multiple virtual hosts with TLS
하나의 Gateway에서 여러 도메인(가상 호스트)에 인증서 구분 적용하기
Istio Gateway는 SNI 기반으로 여러 도메인을 하나의 HTTPS 포트에서 동시에 서빙할 수 있다. 도메인별로 인증서를 구분하고, 서비스를 라우팅해보자.
인증서 시크릿 생성
catalog 서비스 tls 시크릿으로 추가한다.
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 리소스 업데이트
- 하나의 Gateway에서 여러 도메인을 서빙하려면, servers 필드를 배열로 나열하여 각 도메인에 맞는 인증서 시크릿을 지정한다
- webapp 서비스 도메인:
webapp.istioinaction.io
- catalog 서비스 도메인:
catalog.istioinaction.io
- webapp 서비스 도메인:
kubectl apply -f ch4/coolstore-gw-multi-tls.yaml -n istioinaction
VirtualService 생성(catalog)
cat ch4/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
/etc/hosts
도메인 추가
SNI 기반 인증서 확인을 위해 호스트를 추가한다.
# 도메인 질의를 위한 임시 설정 : 실습 완료 후에는 삭제 해둘 것
echo "127.0.0.1 catalog.istioinaction.io" | sudo tee -a /etc/hosts
cat /etc/hosts | tail -n 2
127.0.0.1 webapp.istioinaction.io
127.0.0.1 catalog.istioinaction.io
HTTPS 통신 테스트
✅ 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
두 요청 모두 성공적으로 인증서를 검증하고 정상 응답 반환한다.
TCP traffic : 게이트웨이에서 TCP 사용하기
Exposing TCP ports on an Istio gateway
Istio는 HTTP/HTTPS뿐만 아니라 TCP 기반 서비스도 Gateway를 통해 외부로 노출할 수 있다.
Istio Gateway를 통해 TCP 기반 애플리케이션을 외부에 노출해보자.
TCP Echo 서비스 배포
- 간단한 echo 서버: 텍스트 입력 시 그대로 반사하는 TCP 앱
cat ch4/echo.yaml
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
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
NAME READY STATUS RESTARTS AGE
catalog-6cf4b97d-xpswv 2/2 Running 0 79m
tcp-echo-deployment-584f6d6d6b-gf9bd 0/2 PodInitializing 0 6s
webapp-7685bcb84-z7xjg 2/2 Running 0 79m
Istio IngressGateway에 TCP 포트 추가
• NodePort: 30006 으로 외부에 노출
• Gateway가 외부 TCP 요청을 수신할 수 있도록 포트 열림
# 포트 추가
kubectl patch svc istio-ingressgateway -n istio-system \
--type='json' \
-p='[{"op":"add","path":"/spec/ports/-","value":{"name":"tcp","port":31400,"targetPort":31400,"nodePort":30006,"protocol":"TCP"}}]'
# 아래 포트 추가
...
- name: tcp
nodePort: 30006
port: 31400
protocol: TCP
targetPort: 31400
...
# 확인
kubectl get svc istio-ingressgateway -n istio-system -o jsonpath='{.spec.ports[?(@.name=="tcp")]}'
{"name":"tcp","nodePort":30006,"port":31400,"protocol":"TCP","targetPort":31400}
TCP Gateway & VirtualService 리소스 생성
• Gateway의 port: 31400
• VirtualService의 tcp 매칭 포트도 동일하게 설정
kubectl apply -f ch4/gateway-tcp.yaml -n istioinaction
kubectl apply -f ch4/echo-vs.yaml -n istioinaction
# 확인
kubectl get gw,vs -n istioinaction | grep tcp
gateway.networking.istio.io/echo-tcp-gateway 45s
virtualservice.networking.istio.io/tcp-echo-vs-from-gw ["echo-tcp-gateway"] ["*"] 39s
Telnet을 통한 echo 서비스 호출
• 연결 성공 후, 텍스트를 입력하면 동일한 응답이 반환됨
• echo 서버 동작 정상
• Telnet 세션 종료: Ctrl + ], 이후 quit 입력
이 기능은 MQTT, Redis, PostgreSQL, Kafka 등 다양한 비 HTTP 프로토콜 서비스에서도 유용하게 활용할 수 있다.
Traffic routing with SNI passthrough : TLS는 앱에서, Gateway는 라우팅만!
Istio의 Passthrough TLS + SNI 기반 라우팅은 TLS 트래픽을 Envoy가 복호화하지 않고 그대로 애플리케이션으로 전달할 수 있는 강력한 기능이다.
다시 말해, Istio Gateway에서 TLS에 개입하지 않고 포워딩하여, 애플리케이션에서 TLS를 수행한다.
TODO: gw는 라우팅 pass through 하여 애플리케이션에서 TLS 처리하는 그림 그리기
TLS 인증을 istio-ingressgateway에서 처리하는 것이 아닌 애플리케이션에서 TLS 처리
앱에서 TLS 처리 (Passthrough 대상 서비스 배포)
kubectl apply -f ch4/sni/simple-tls-service-1.yaml -n istioinaction
Gateway 구성 - PASSTHROUGH 모드
• mode: PASSTHROUGH는 TLS 핸드셰이크를 Envoy가 수행하지 않고 그대로 서비스로 넘긴다.
# 기존 Gateway 명세(echo-tcp-gateway) 제거 : istio-ingressgateway의 동일한 port (31400, TCP)를 사용하므로 제거함
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 설정 (SNI 기반)
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 서비스 포트로 라우팅
통신 테스트 (SNI 도메인에 맞는 인증서로 요청)
# 호출테스트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
...
{
"name": "simple-tls-service-1",
"uri": "/",
"type": "HTTP",
"ip_addresses": [
"10.10.0.15"
],
"start_time": "2025-04-17T14:10:44.633943",
"end_time": "2025-04-17T14:10:44.638863",
"duration": "4.919ms",
"body": "Hello from simple-tls-service-1!!!",
"code": 200
}
라우팅을 더 명확하게 하기 위해, 인증서가 다른, 두 번째 서비스를 배포하여, SNI 라우팅 테스트를 진행한다.
#
kubectl apply -f ch4/sni/simple-tls-service-2.yaml -n istioinaction
# gateway 설정 업데이트
cat ch4/sni/passthrough-sni-gateway-both.yaml
...
hosts:
- "simple-sni-1.istioinaction.io"
tls:
mode: PASSTHROUGH
- port:
number: 31400
name: tcp-sni-2
protocol: TLS
hosts:
- "simple-sni-2.istioinaction.io"
tls:
mode: PASSTHROUGH
...
kubectl apply -f ch4/sni/passthrough-sni-gateway-both.yaml -n istioinaction
# VirtualService 설정
cat ch4/sni/passthrough-sni-vs-2.yaml
kubectl apply -f ch4/sni/passthrough-sni-vs-2.yaml -n istioinaction
최종 테스트
신규 도메인 추가 및 인증서 확인
# 인증서1 도메인 확인: imple-sni-1.istioinaction.io
openssl x509 -in ch4/sni/simple-sni-1/2_intermediate/certs/ca-chain.cert.pem -noout -text | grep -i cn
Issuer: C=US, ST=Denial, L=Springfield, O=Dis, CN=simple-sni-1.istioinaction.io
Subject: C=US, ST=Denial, O=Dis, CN=simple-sni-1.istioinaction.io
# 인증서2 도메인 확인: imple-sni-2.istioinaction.io
openssl x509 -in ch4/sni/simple-sni-2/2_intermediate/certs/ca-chain.cert.pem -noout -text | grep -i cn
Issuer: C=US, ST=Denial, L=Springfield, O=Dis, CN=simple-sni-2.istioinaction.io
Subject: C=US, ST=Denial, O=Dis, CN=simple-sni-2.istioinaction.io
❌ 실패: 인증서 1로 서비스 2 접근
# 인증서 불일치로 TLS 연결 실패
curl https://simple-sni-2.istioinaction.io:30006 \
--cacert ch4/sni/simple-sni-1/2_intermediate/certs/ca-chain.cert.pem
✅ 성공: 인증서 2로 서비스 2 접근
curl https://simple-sni-2.istioinaction.io:30006 \
--cacert ch4/sni/simple-sni-2/2_intermediate/certs/ca-chain.cert.pem
{
"name": "simple-tls-service-2",
...
"body": "Hello from simple-tls-service-2!!!"
}
SNI 값에 따라 Gateway가 트래픽을 단순히 포워딩(Passthrough) 하고, 각 앱에서 인증서를 기반으로 TLS를 처리하고 응답하는 것을 확인할 수 있다.
🔐 Istio TLS 모드 요약
TLS 모드 | 설명 | 인증서 처리 주체 | 사용 예시 |
---|---|---|---|
SIMPLE | Gateway가 TLS 연결을 종료(Terminate)하고 인증서를 검증함 | Istio Gateway (Envoy) | 기본 HTTPS 서비스 구성 |
MUTUAL | Gateway가 클라이언트의 인증서도 검증하는 상호 TLS(mTLS) | Istio Gateway (Envoy) | 내부 서비스 간 인증, 민감한 API 호출 |
PASSTHROUGH | Gateway는 TLS를 종료하지 않고 트래픽을 그대로 애플리케이션으로 전달 | 서버 애플리케이션 (직접) | 앱이 직접 인증서 처리할 때 (ex. 기존 TLS 시스템) |
Operational tips : 실전에서 Istio Gateway를 더 똑똑하게 활용하는 방법들
게이트웨이 역할 분리 (Split Gateway Responsibilities)
게이트웨이를 기능별/트래픽별로 나누어 구성하면 확장성과 운영 안정성이 향상된다.
예를들어, 이미지 레지스트리, 대용량 이벤트 수신 API 등 트래픽 특성이 다른 서비스는 전용 Gateway(예: my-user-gateway)를 만들어 격리한다.
IstioOperator
리소스를 통해 포트, 노드포트, 라벨 등 세부 설정 가능하며, 기존 istio-ingressgateway는 비활성화할 수 있다.
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
게이트웨이 주입 (Gateway Injection)
미완성 subbed-out 게이트웨이 디플로이먼트를 배포하고 이스티오가 나머지를 채우는 방식으로, 사이드카 주입이 이뤄지는 방식과 비슷하다.
사용자에게 IstioOperator 전체 접근 권한을 갖지 않아도, 자체 게이트웨이를 만들수 있게 허용할 수 있어, 운영 시 유용하다.(역할 분리)
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 미완성 이미지
...
인그레스 게이트웨이 로그 확인 (Ingress Gateway Access Logs)
액세스 로그란 프로시(Envoy)의 핵심 기능 중 하나로, 처리한 모든 요청을 로그로 기록하는 것이다. 이 로그는 문제를 해결, 디버깅, 분석 등에서 매우 유용하다.
하지만, Istio는 워크로드의 수 많은 트래픽을 처리하기 때문에, 기본 설치 프로필(default profile) 액세스 로그는 기본적으로 비활성화되어있다..
Access 로그를 출력하도록 하기 위해서는 해당 configmap의 아래 내용을 추가하자.
# configmap 에 mesh 바로 아래에 accessLogFile 부분 추가됨
kubectl get cm -n istio-system istio -o yaml
...
mesh: |-
accessLogFile: /dev/stdout
...
Telemetry 사용
텔레메트리 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 로 설정해 활성화한다
게이트웨이 설정 최적화 (Reducing Gateway Configuration)
Istio Gateway는 불필요하게 많은 라우팅 설정을 받을 필요가 없다. PILOT_FILTER_GATEWAY_CLUSTER_CONFIG
설정을 통해
정말 필요한 설정만 반영되도록 최적화하면, 운영 안정성과 성능 모두 개선할 수 있다.
PILOT_FILTER_GATEWAY_CLUSTER_CONFIG 활성화하여, Gateway에 연결된 VirtualService 리소스가 실제로 참조하는 서비스 클러스터 정보만 해당 Gateway 프록시에 전달하도록 설정한다.
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
사이드카 설정 제한 (Sidecar)
각 워크로드(예: Service A)에 Sidecar 리소스를 정의하여, 해당 Envoy 프록시가 접근하거나 알 수 있는 외부/내부 서비스 범위를 제한할 수 있다.
apiVersion: networking.istio.io/v1beta1
kind: Sidecar
metadata:
name: service-a-v1
spec:
egress:
- hosts:
- ./hackjap.blog.service
workloadSelector:
labels:
app: service-a
version: v1
'Infrastructure' 카테고리의 다른 글
Istio 시리즈 # 5 – 네트워크 복원력 강화하기(Resilience) (0) | 2025.04.27 |
---|---|
Istio 시리즈 # 4 – 세밀하게 트래픽 제어하기(Traffic Control) (0) | 2025.04.27 |
Istio 시리즈 # 2 - Istio의 핵심, Envoy Proxy를 이해하자 (0) | 2025.04.20 |
Istio 시리즈 # 1 - 설치부터 기본 트레픽 제어까지 (0) | 2025.04.13 |
개발자(엔지니어)에게 꼭 필요한 기초 암호학(X.509) (0) | 2025.03.15 |