4.2.3 Overall view of traffic flow 전체적인 트래픽 흐름 개요
이스티오 게이트웨이 리소스는 서비스 메시 클러스터의 엣지에서 리스닝하고자 하는 포트, 프로토콜, 가상 호스트를 정의한다.
VirtualService 리소스는 에지에서 허용된 트래픽이 가야 할 곳을 정의한다.
4.2.4 Istio ingress gateway vs. Kubernetes Ingress
쿠버네티스를 실행할 때 ‘왜 이스티오는 그냥 쿠버네티스 인그레스 v1 리소스를 인그레스로 지정하지 않는가?’ 라는 의문이 생길 수 있다. 이스티오는 쿠버네티스 인그레스 v1 리소스를 지원하지만, 쿠버네티스 인그레스 v1 사양에는 상당한 한계가 있다.
- 쿠버네티스 인그레스 v1 의 사양이 HTTP 워크로드에 맞춰져 매우 단순하다는 점
- 실제로 인그레스 사양은 80 포트와 443 포트만 인그레스 포인트로 간주한다. 이는 클러스터 운영자가 서비스 메시로 허용할 수 있는 트래픽 유형을 심각하게 제한한다.
- 예를 들어 카프카나 NATS.io 워크로드가 있다면, 이들 메시지 시스템에 TCP 커넥션을 직접 노출하고 싶을 수 있다. 쿠버네티스 인그레스는 이를 허용하지 않는다.
- 쿠버네티스 인그레스 v1 리소스는 사양이 심각하게 부족하다는 점
- 복잡한 트래픽 라우팅 규칙, 트래픽 분할, 트래픽 섀도잉 같은 것들을 지정하는 일반적인 방법이 없다.
- 이런 영역에서 사양이 부족한 까닭에 각 벤더는 인그레스 구현체(HAProxy, Nginx 등)에서 설정의 최적 구현법을 재창조해야했다.
- 사양이 부족하다 보니 벤더 대부분의 설정이 디플로이먼트의 맞춤형 애노테이션으로 노출하는 방식을 택했다는 점
- 이 애노테이션은 벤더마다 상이하고 호환되지 않으므로, 이스티오가 이런 추세에 따랐다면 에지 게이트웨이로서 엔보이의 모든 기능을 반영하기 위해 애노테이션이 더 많이 필요했을 것이다.
결국 이스티오는 인그레스 패턴을 백지 상태에서 시작해 구축하기로 결정했고, 4계층(전송)과 5계층(세션) 속성을 7계층(애플리케이션) 라우팅 문제로부터 명확하게 분리해냈다. 이스티오 Gateway는 L4/L5 문제를 처리하고, VirtualService는 L7 문제를 처리한다.
Notes
- 이 책을 저술하는 시점(’21~22년)에 쿠버네티스 커뮤니티는 인그레스 v1 API를 대체하고자 Gateway API를 열심히 준비하고 있다.
- 이 API는 책에서 다룬 Istio Gateway 및 VirtualService 리소스와 다르다.
- Istio의 구현체와 리소스는 Gateway API 보다 먼저 등장했고, 여러 면에서 Gateway API에 영감을 줬다.
4.2.5 Istio ingress gateway vs. API gateways
API 게이트웨이는 조직이 네트워크나 아키텍처 경계의 서비스를 사용하는 클라이언트에게 서비스 구현의 세부 사항을 추상화활 수 있게 해준다.
- 클라이언트는 잘 문서화된 API들을 호출하게 되고, 이 API들은 앞뒤 호환성을 지니면서 발전하며, 셀프 서비스와 기타 사용 메커니즘을 제공할 수 있다.
- 이를 달성하려면 API 게이트웨이는 여러 보안 기술(OIDC, OAuth 2.0, LDAP)을 사용해 클라이언트를 식별할 수 있어야 하고, 메시지를 변형할 수 있어야 하며(SOAP → REST, gRPC → REST, 바디 및 헤더 텍스트 기반 변환 등), 비즈니스 수준으로 정교하게 속도를 제한할 수 있어야 하고, 자체 가입 기능이나 개발자 포털을 제공할 수 있어야 한다.
- 이스티오의 인그레스 게이트웨이는 이런 것들을 기본적으로는 제공하지 않는다.
- 메시 안팎에서 이런 역할을 수행하는 더욱 강력한 API 게이트웨이를 찾는다면, 엔보이 프록시를 기반으로 하는 Solo.io Gloo Edge 같은 것을 살펴볼만 한다.
4.3 Securing gateway traffic 게이트웨이 트래픽 보안
지금까지 Gateway, VirtualService 리소스를 사용해 이스티오 게이트웨이에서 기본 HTTP 서비스를 노출하는 방법을 살펴봤다.
- 클러스터 외부(퍼블릭 인터넷 등)의 서비스를 클러스터 내부에서 실행 중인 서비스에 연결할 때, 인그레스 게이트웨이의 기본 기능 중 하나는 트래픽을 보호해 시스템의 신뢰 구축을 돕는 것이다.
- 트래픽 보호는 클라이언트가 통신하려는 서버의 진위를 가리는 것에서 시작할 수 있다. 자신이 그 서비스라고 주장하는 서비스가 정말 통신하려는 서비스가 맞는지 검증하는 것이다. 또한 누군가가 도청하는 일을 막고 싶으므로 트래픽을 암호화해야 한다.
- 이스티오의 게이트웨이 구현을 사용하면 들어오는 TLS/SSL 트래픽을 종료하고, 백엔드 서비스로 전달하고, TLS가 아닌 트래픽을 적절한 TLS 포트로 리다이렉트하고, mTLS를 구현할 수 있다.
4.3.1 HTTP traffic with TLS (실습)
MITM 공격을 방지하고 서비스 메시로 들어오는 모든 트래픽을 암호화하기 위해 이스티오 게이트웨이에 TLS를 설정할 수 있다. 들어오는 트래픽 모두가 HTTPS로 제공되도록 하는 것이다.
- MITM 공격이란 클라이언트가 어떤 서비스에 연결하려고 하지만, 그 서비스가 아닌 사칭 서비스에 언결할 때를 말한다. 사칭 서비스는 통신에 접근할 수 있게 되며, 여기에는 민감 정보도 포함된다. TLS는 이 공격을 완화하는 데 도움을 준다.
수신 트래픽에 HTTPS를 활성화하려면 게이트웨이가 사용할 비공개 키와 인증서를 올바르게 지정해야 한다. 서버가 제시하는 인증서는 서버가 클라이언트에게 자신의 정체를 알리는 방법이다.
- 인증서란 기본적으로 서버의 공개 키이며, 신뢰할 수 있는 기관인 인증 기관 (CA, Certificate Authority)에서 서명한 것이다.
아래 그림은 클라이언트가 서버 인증서의 유효성을 판단하는 방법을 도식화한 것이다.
- 먼저 클라이언트에 CA 발급자의 인증서가 설치돼 있어야 한다.
- 이는 이 발급자가 신뢰할 수 있는 CA이며 발급자가 발급한 인증서 역시 신뢰할 수 있다는 의미다.
- CA 인증서가 설치돼 있으면, 클라이언트는 인증서가 신뢰할 수 있는 CA가 서명한 것인지 검증할 수 있다.
- 그런 다음, 클라이언트는 인증서 내 공개 키를 사용해 서버로 보내는 트래픽을 암호화 한다.
- 서버는 비밀 키로 트래픽을 복호화 할 수 있다.
Notes
앞 선 설명은 사실 정확하지 않다. TLS handshake 에는 더 정교한 프로토콜이 포함되는데, 최초 통신에는 공개/비공개 키(비대칭)를 조합하고, TLS 세션에서 트래픽 암호화/복호화에 사용할 세션 키(대칭)을 생성한다.
기본 istio-ingressgateway 가 인증서와 키를 사용하도록 설정하려면 먼저 인증서/키를 쿠버네티스 시크릿으로 만들어야 한다.
#
docker exec -it myk8s-control-plane istioctl proxy-config secret deploy/istio-ingressgateway.istio-system
RESOURCE NAME TYPE STATUS VALID CERT SERIAL NUMBER NOT AFTER NOT BEFORE
default Cert Chain ACTIVE true 5384840145379860934113500875842526824 2025-04-14T11:51:01Z 2025-04-13T11:49:01Z
ROOTCA CA ACTIVE true 218882737649632505517373517490277818381 2035-04-11T11:50:53Z 2025-04-13T11:50:53Z
# 파일 정보 확인
cat ch4/certs/3_application/private/webapp.istioinaction.io.key.pem # 비밀키(개인키)
cat ch4/certs/3_application/certs/webapp.istioinaction.io.cert.pem
openssl x509 -in ch4/certs/3_application/certs/webapp.istioinaction.io.cert.pem -noout -text
...
Issuer: C=US, ST=Denial, O=Dis, CN=webapp.istioinaction.io
Validity
Not Before: Jul 4 12:49:32 2021 GMT
Not After : Jun 29 12:49:32 2041 GMT
Subject: C=US, ST=Denial, L=Springfield, O=Dis, CN=webapp.istioinaction.io
...
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Cert Type:
SSL Server
Netscape Comment:
OpenSSL Generated Server Certificate
X509v3 Subject Key Identifier:
87:0E:5E:A4:4C:A5:57:C5:6D:97:95:64:C4:7D:60:1E:BB:07:94:F4
X509v3 Authority Key Identifier:
keyid:B9:F3:84:08:22:37:2C:D3:75:18:D2:07:C4:6F:4E:67:A9:0C:7D:14
DirName:/C=US/ST=Denial/L=Springfield/O=Dis/CN=webapp.istioinaction.io
serial:10:02:12
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
...
# 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
webapp-credential을 istio-system 네임 스페이스에 시크릭으로 생성한다. 게이트웨이의 TLS에서 사용하는 시크릿은 이스티오 인그레스 게이트웨이와 동일한 네임스페이스에 있을 때만 가져올 수 있다. (이 책이 저술되었을 시점에)
운영 환경에서는 인그레스 게이트웨이를 istio-system과 분리해 자체 네임스페이스에서 실행해야 한다.
이렇게 secret 리소스를 생성해서 이스티오 게이트웨이 리소스가 인증서와 키를 사용하도록 설정할 수 있다.
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"
Gateway 리소스에서 인그레스 게이트웨이의 443 포트를 열고, 이를 HTTPS로 지정한다. 또한 게이트웨이 설정에 tls 부분을 추가해 TLS에 사용할 인증서와 키의 위치를 지정한다. 이 위치가 앞서 istio-ingressgateway 에 마운트한 위치와 동일하다는 것을 확인하자.
#
cat ch4/coolstore-gw-tls.yaml
kubectl apply -f ch4/coolstore-gw-tls.yaml -n istioinaction
gateway.networking.istio.io/coolstore-gateway configured
#
docker exec -it myk8s-control-plane istioctl proxy-config secret deploy/istio-ingressgateway.istio-system
RESOURCE NAME TYPE STATUS VALID CERT SERIAL NUMBER NOT AFTER NOT BEFORE
default Cert Chain ACTIVE true 135624833228815846167305474128694379500 2025-04-14T03:57:41Z 2025-04-13T03:55:41Z
kubernetes://webapp-credential Cert Chain ACTIVE true 1049106 2041-06-29T12:49:32Z 2021-07-04T12:49:32Z
ROOTCA CA ACTIVE true 236693590886065381062210660883183746411 2035-04-11T03:57:31Z 2025-04-13T03:57:31Z
# 호출 테스트 1
curl -v -H "Host: webapp.istioinaction.io" https://localhost:30005/api/catalog
* Host localhost:30005 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:30005...
* Connected to localhost (::1) port 30005
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
* 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
# 서버(istio-ingressgateway 파드)에서 제공하는 인증서는 기본 CA 인증서 체인을 사용해 확인할 수 없다는 의미다.
# curl 클라이언트에 적절한 CA 인증서 체인을 전달해보자.
# (호출 실패) 원인: (기본 인증서 경로에) 인증서 없음. 사설인증서 이므로 “사설CA 인증서(체인)” 필요
#
kubectl exec -it deploy/istio-ingressgateway -n istio-system -- ls -l /etc/ssl/certs
...
lrwxrwxrwx 1 root root 23 Oct 4 2023 f081611a.0 -> Go_Daddy_Class_2_CA.pem
lrwxrwxrwx 1 root root 47 Oct 4 2023 f0c70a8d.0 -> SSL.com_EV_Root_Certification_Authority_ECC.pem
lrwxrwxrwx 1 root root 44 Oct 4 2023 f249de83.0 -> Trustwave_Global_Certification_Authority.pem
lrwxrwxrwx 1 root root 41 Oct 4 2023 f30dd6ad.0 -> USERTrust_ECC_Certification_Authority.pem
lrwxrwxrwx 1 root root 34 Oct 4 2023 f3377b1b.0 -> Security_Communication_Root_CA.pem
lrwxrwxrwx 1 root root 24 Oct 4 2023 f387163d.0 -> Starfield_Class_2_CA.pem
lrwxrwxrwx 1 root root 18 Oct 4 2023 f39fc864.0 -> SecureTrust_CA.pem
lrwxrwxrwx 1 root root 20 Oct 4 2023 f51bb24c.0 -> Certigna_Root_CA.pem
lrwxrwxrwx 1 root root 20 Oct 4 2023 fa5da96b.0 -> GLOBALTRUST_2020.pem
...
#
cat ch4/certs/2_intermediate/certs/ca-chain.cert.pem
openssl x509 -in ch4/certs/2_intermediate/certs/ca-chain.cert.pem -noout -text
...
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
...
# 호출 테스트 2
curl -v -H "Host: webapp.istioinaction.io" https://localhost:30005/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem
* Host localhost:30005 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:30005...
* Connected to localhost (::1) port 30005
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
* 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
# (호출 실패) 원인: 인증실패. 서버인증서가 발급된(issued) 도메인 “webapp.istioinaction.io”로 호출하지 않음 (localhost로 호출함)
# 도메인 질의를 위한 임시 설정 : 실습 완료 후에는 삭제 해둘 것
echo "127.0.0.1 webapp.istioinaction.io" | sudo tee -a /etc/hosts
cat /etc/hosts | tail -n 1
# 호출 테스트 3
curl -v https://webapp.istioinaction.io:30005/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem
open https://webapp.istioinaction.io:30005
open https://webapp.istioinaction.io:30005/api/catalog
# http 접속도 확인해보자
curl -v http://webapp.istioinaction.io:30000/api/catalog
open http://webapp.istioinaction.io:30000
왜 그런지 모르겠지만 CApath가 있는 것으로 보인다. 기대했던 호출 테스트 값과는 다르게 반환되어서 이유를 확인하고 싶었다.
GPT에게 물어보니 결과에 대한 원인은 같다고 느껴진다. 그럼 curl 버전이 달라서 반환 값이 다른지는 아닌지 물어보았다.
[기대 값]
* LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to localhost:30005
[반환 값]
error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
GPT 말을 일단 믿어보고 넘어가보려 한다. 결국 TLS 통신이 안된다는 이유는 같으니 실습 결과대로 진행되고 있다고 이해가 된다.
ssl cert를 확인하면 584개나 있는 것으로 보인다. 저 중에 ca에 대한 cert chain이 없어서 TLS 통신이 안되고 있는 것이다.
이번엔 다른 cert chain으로 통신을 시도한다. 서버 인증서가 발급 된 도메인인 webapp.istioinaction.io로 통신 하지 않아서 실패 했다.
/etc/hosts 파일에 해당 도메인을 등록해준다.
SSL certificate verify ok로 정상적으로 인증서 확이 되는 것을 알 수 있다.
웹에서도 동일하게 확인 하고 싶었는데 확인 할 수 없다. 왜냐면 hosts 파일에 동일하게 설정 해줘야 하기 때문이다.
C:\Windows\System32\drivers\etc 에 있는 hosts 파일을 수정해주자
흠... 그래도 인증서 인증이 안되는데...
인증서 기간이나 다른 정보도 다 동일한 것으로 보인다. 뭐 접속은 일단 되긴 하는데 왜 그런지는 나중에 한번 더 확인 해봐야겠다.
위 그림은 종단 간 end-to-end 암호화를 달성했음을 보여준다.
우리는 이스티오 게이트웨이를 향하는 트래픽을 암호화함으로써 보호한다.
이스티오 인그레스 게이트웨이는 TLS 커넥션을 종료하고, 트래픽을 서비스 메시 내에서 실행 중인 뒷단의 webapp 서비스로 보낸다.
istio-ingressgateway 와 webapp 서비스 사이의 홉은 서비스의 ID를 사용해 암호화한다. 9장에서 살펴볼 것이다.
4.3.2 HTTP redirect to HTTPS (실습)
모든 트래픽 항상 TLS를 쓰도록 강제, HTTP 트래픽을 강제로 리다이렉트하게 Gateway 수정
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 버전을 호출하라고 지시한다.
4.3.3 HTTP traffic with mutual TLS (실습)
앞 절에서는 표준 TLS를 사용해 서버가 자신의 정체를 클라이언트에게 증명하게 했다. 그런데 만약 클러스터 외부의 트래픽을 받아들이기 전에 클라이언트가 누군지 검증하고 싶다면 어떻게 해야 할까?
단순 TLS 시나리오에서는 서버가 자신의 공개 인증서를 클라이언트에게 보냈고, 클라이언트는 서버의 인증서에 서명한 CA를 신뢰할 수 있음을 검증했다. 우리는 클라이언트가 자신의 공개 인증서를 보내게 하고 서버가 인증서를 신뢰하는지 검증하게 하고 싶다.
아래 그림은 mTLS 프로토콜에서 클라이언트와 서버 모두가 어떻게 서로의 인증서를 검증하는지, 즉 어떻게 서로 인증하는지 보여준다.
기본 istio-ingressgateway 가 mTLS 커넥션에 참여하도록 구성하려면, 클라이언트의 인증서를 검증하는 데 사용할 수 있도록 CA 인증서 집합을 제공해야 한다. 앞 절에서 했던 것처럼, 쿠버네티스 시크릿으로 istio-ingressgateway 에세 이 CA 인증서(더 구체적으로 인증서 체인)를 사용할 수 있게 해야 한다.
적절한 CA 인증서 체인으로 istio-ingressgateway-ca-cert 시크릿을 구성하는 것으로 시작하겠다.
# 인증서 파일들 확인
cat ch4/certs/3_application/private/webapp.istioinaction.io.key.pem
cat ch4/certs/3_application/certs/webapp.istioinaction.io.cert.pem
cat ch4/certs/2_intermediate/certs/ca-chain.cert.pem
openssl x509 -in ch4/certs/2_intermediate/certs/ca-chain.cert.pem -noout -text
# 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
이제 CA 인증서 체인의 위치를 가리키도록 이스티오 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
gateway.networking.istio.io/coolstore-gateway configured
# (옵션) SDS 로그 확인
kubectl stern -n istio-system -l app=istiod
istiod-7df6ffc78d-w9szx discovery 2025-04-13T08:14:14.405397Z info ads SDS: PUSH request for node:istio-ingressgateway-996bc6bb6-p6k79.istio-system resources:0 size:0B cached:0/0 filtered:2
...
#
docker exec -it myk8s-control-plane istioctl proxy-config secret deploy/istio-ingressgateway.istio-system
RESOURCE NAME TYPE STATUS VALID CERT SERIAL NUMBER NOT AFTER NOT BEFORE
default Cert Chain ACTIVE true 135624833228815846167305474128694379500 2025-04-14T03:57:41Z 2025-04-13T03:55:41Z
ROOTCA CA ACTIVE true 236693590886065381062210660883183746411 2035-04-11T03:57:31Z 2025-04-13T03:57:31Z
kubernetes://webapp-credential Cert Chain ACTIVE true 1049106 2041-06-29T12:49:32Z 2021-07-04T12:49:32Z
kubernetes://webapp-credential-mtls Cert Chain ACTIVE true 1049106 2041-06-29T12:49:32Z 2021-07-04T12:49:32Z
kubernetes://webapp-credential-mtls-cacert CA ACTIVE true 1049106 2041-06-29T12:49:29Z 2021-07-04T12:49:29Z
# 호출 테스트 1 : (호출실패) 클라이언트 인증서 없음 - SSL 핸드섀이크가 성공하지 못하여 거부됨
curl -v https://webapp.istioinaction.io:30005/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem
# 웹브라우저에서 확인 시 클라이언트 인증서 확인되지 않아서 접속 실패 확인
open https://webapp.istioinaction.io:30005
open https://webapp.istioinaction.io:30005/api/catalog
# 호출 테스트 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이다. 서비스 프록시도 마찬가지다.
4.3.4 Serving multiple virtual hosts with TLS (실습)
이스티오의 인그레스 게이트웨이는 동일한 HTTPS 포트(443)에서 자체 인증서와 비밀 키가 있는 여러 가상 호스트를 서빙할 수 있다. 이를 위해 동일 포트 및 프로토콜에 여러 항목을 추가한다. 예를 들어 자체 인증서와 키 쌍이 있는 webapp.istioinaction.io 와 catalog.istioinaction.io 서비스를 둘 다 추가할 수 있다.
HTTPS로 서빙하는 가상 호스트를 여럿 기술하고 있는 이스티오 Gateway 리소스는 다음과 같다.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: coolstore-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 443
name: https-webapp
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: webapp-credential
hosts:
- "webapp.istioinaction.io"
- port:
number: 443
name: https-catalog
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: catalog-credential
hosts:
- "catalog.istioinaction.io"
둘 다 443 포트 리스닝하고 HTTPS 를 서빙하지만, 호스트이름이 다르다는 것을 유의하자.
각 항목에는 서빙하는 가상 호스트용으로 사용하는 고유한 인증서와 키가 있다. 이를 위해 인증서와 키를 추가하자.
#
cat ch4/certs2/3_application/private/catalog.istioinaction.io.key.pem
cat ch4/certs2/3_application/certs/catalog.istioinaction.io.cert.pem
openssl x509 -in ch4/certs2/3_application/certs/catalog.istioinaction.io.cert.pem -noout -text
...
Issuer: C=US, ST=Denial, O=Dis, CN=catalog.istioinaction.io
Validity
Not Before: Jul 4 13:30:38 2021 GMT
Not After : Jun 29 13:30:38 2041 GMT
Subject: C=US, ST=Denial, L=Springfield, O=Dis, CN=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 리소스 생성
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
kubectl get gw,vs -n istioinaction
# 도메인 질의를 위한 임시 설정 : 실습 완료 후에는 삭제 해둘 것
echo "127.0.0.1 catalog.istioinaction.io" | sudo tee -a /etc/hosts
cat /etc/hosts | tail -n 2
# 호출테스트 1 - webapp.istioinaction.io
curl -v https://webapp.istioinaction.io:30005/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem
# 호출테스트 2 - catalog.istioinaction.io (cacert 경로가 ch4/certs2/* 임에 유의)
curl -v https://catalog.istioinaction.io:30005/items \
--cacert ch4/certs2/2_intermediate/certs/ca-chain.cert.pem
두 호출 모두 동일한 응답으로 성공했다. 그런데 발신자마다 어떤 인증서를 제시해야 하는지를 이스티오 인그레스가 어떻게 아는지가 궁금할 수 있다. 이 커넥션들이 열린 포트는 하나인데, 게이트웨이는 클라이언트가 접근하려는 서비스가 어느것이고 그 서비스에 해당하는 인증서가 어느 것인지를 알 수 있을까?
해답은 SNI(서버 이름 표시)라는 TLS 확장에 있다.
기본적으로 HTTPS 커넥션이 만들어지면 클라이언트는 먼저 TLS 핸드셰이크의 ClientHello 부분에서 어느 서비스에 접근해야 하는지부터 전달한다.
이스티오의 게이트웨이(엄밀히는 엔보이)가 TLS의 SNI를 구현하는 덕분에 올바른 인증서를 제시할 수 있고 올바른 서비스로 라우팅 할 수 있는 것이다.
HTTPS 경우 TLS CliendHello 의 SNI의 Server Name 에서 주소를 확인 후 통제합니다.
- Squid v3.5 부터 SslPeekAndSplice 기능으로 TLS ClientHello 의 SNI 값(URL 주소) 기반 통제 가능
4.4 TCP traffic
들어가며
이스티오 게이트웨이는 HTTP/HTTPS 트래픽뿐 아니라 TCP로 접근하는 모든 트래픽을 처리할 수 있다.
- 예를 들어, 인그레스 게이트웨이로 데이터베이스(MongoDB 등)나 메시지 큐(카프카 등)를 노출할 수 있다.
이스티오가 트래픽을 단순 TCP로 다루면 재시도, 요청 수준 서킷 브레이킹, 복잡한 라우팅 등과 같은 유용한 기능을 사용할 수 없다. 단순히 이스티오가 어떤 프로토콜을 사용하는지 분간할 수 없기 때문이다. (MongoDB 처럼 이스티오-엔보이가 이해하는 프로토콜을 사용하는 것이 아닌 이상).
클러스터 외부의 클라이언트가 클러스터 내에서 실행 중인 서비스와 통신할 수 있도록 이스티오 게이트웨이에 TCP 트래픽을 노출하는 방법을 알아보자.
4.4.1 Exposing TCP ports on an Istio gateway (실습) → 실습 컨테이너 이미지를 istio-echo-server 변경 만들어 둘것 - Link, Dockerhub
가장 먼저 해야 할일은 서비스 메시 내에서 TCP 기반 서비스를 만드는 것이다.
이 예제는 깃허브의 에코 서비스를 사용한다. https://github.com/cjimti/go-echo
이 TCP 서비스는 Telnet 같은 간단한 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
tcp-echo-deployment-584f6d6d6b-xcpd8 2/2 Running 0 27s
...
# tcp 서빙 포트 추가 : 편집기는 vi 대신 nano 선택 <- 편한 툴 사용
KUBE_EDITOR="nano" kubectl edit svc istio-ingressgateway -n istio-system
...
- 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}
# 게이트웨이 생성
cat ch4/gateway-tcp.yaml
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 리소스 생성
cat ch4/echo-vs.yaml
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
NAME GATEWAYS HOSTS AGE
catalog-vs-from-gw ["coolstore-gateway"] ["catalog.istioinaction.io"] 44m
tcp-echo-vs-from-gw ["echo-tcp-gateway"] ["*"] 6s
webapp-vs-from-gw ["coolstore-gateway"] ["webapp.istioinaction.io"] 3h59m
# mac 에 telnet 설치
brew install telnet
#
telnet localhost 30006
Trying ::1...
Connected to localhost.
Escape character is '^]'.
Welcome, you are connected to node myk8s-control-plane.
Running on Pod tcp-echo-deployment-584f6d6d6b-xcpd8.
In namespace istioinaction.
With IP address 10.10.0.20.
Service default.
hello istio! # <-- type here
hello istio! # <-- echo here
# telnet 종료하기 : 세션종료 Ctrl + ] > 텔넷 종료 quit
tcp를 서빙하기 위한 포트를 istio-ingressgateway 에 추가 해준다.
정상적으로 추가 되었음을 확인할 수 있다.
에코 서비스로 라우팅하기 위해서 gateway 와 virtualservice 를 생성 해준다.
telnet으로 정상 접속 확인!
4.4.2 Traffic routing with SNI passthrough (실습)
이번 절에서는 두 기능의 조합. 즉 이스티오 인그레스 게이트웨이에서 트래픽을 종료하지 않고 SNI 호스트네임에 따라 TCP 트래픽을 라우팅하는 방법을 다룬다.
게이트웨이가 하는 일은 SNI 헤더를 살펴보고 트래픽을 특정 백엔드로 라우팅하는 것 뿐이다. TLS 커넥션 종료는 그 후 백엔드에서 처리한다. 커넥션은 게이트웨이를 ‘통과 passthrough’ 하고, 처리는 게이트웨이가 아닌 실제 서비스가 담당하게 된다.
이런 방식은 서비스 메시에 참여할 수 있는 애플리케이션의 범위를 휠씬 넓혀준다. 데이터베이스, 메시지 큐, 캐시 등과 같은 TLS 상의 TCP 서비스는 물론, HTTPS/TLS 트래픽을 직접 처리하고 종료할 것이라고 예상되는 레거시 애플리케이션까지도 포함될 수 있다.
Gateway 살펴보자
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를 종료하는 예제 에플리케이션을 배포하는 것부터 시작하자.
# TLS 인증을 직접 처리하는 앱 배포. (gw는 route 만 처리, pass through )
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) 제거 : 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 리소스 라우팅 규칙 지정하자
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
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
curl 호출은 이스티오 인그레스 게이트웨이로 갔다가, 종료 없이 예제 서비스 simple-tls-service-1 에 도달한다.
라우팅을 더 명확하게 하기 위해 인증서가 다르고 SNI 호스트에 기반해 라우팅을 하는 두 번째 서비스를 배포해보자.
# 두 번째 서비스 배포
cat ch4/sni/simple-tls-service-2.yaml
kubectl apply -f ch4/sni/simple-tls-service-2.yaml -n istioinaction
# gateway 설정 업데이트
cat ch4/sni/passthrough-sni-gateway-both.yaml
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
# 호출테스트2
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
이 요청을 simple-tls-sni-2 서비스가 서빙했음을 body 필드의 응답이 어떻게 알려주는지 주목하자.
4.5 Operational tips 운영 팁
```실습 참고 https://netpple.github.io/docs/istio-in-action/Istio-ch4-4-tips```
4.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
exit
------------------------------------------
# IstioOperator 확인
kubectl get IstioOperator -A
NAMESPACE NAME REVISION STATUS AGE
istio-system installed-state 5h48m
istioinaction my-user-gateway-install 17s
#
kubectl get deploy my-user-gateway -n istioinaction
NAME READY UP-TO-DATE AVAILABLE AGE
my-user-gateway 1/1 1 1 65s
# 포트 확인
kubectl get svc my-user-gateway -n istioinaction -o yaml
...
- name: tcp
nodePort: 30007
port: 31400
protocol: TCP
targetPort: 31400
...
실습 : 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 명세
cat ch4/echo-vs.yaml
kubectl apply -f ch4/echo-vs.yaml -n istioinaction
# 앱 배포
cat ch4/echo.yaml
kubectl apply -f ch4/echo.yaml -n istioinaction
# 호출 테스트 : NodePort 30007로 접속 테스트
telnet localhost 30007
Trying ::1...
Connected to localhost.
Escape character is '^]'.
..
Service default.
hello Istio # <-- type here
hello Istio # <-- echo here
# telnet 종료하기 : 세션종료 Ctrl + ] > 텔넷 종료 quit
4.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 미완성 이미지
...
#
cat ch4/my-user-gw-injection.yaml
kubectl apply -f ch4/my-user-gw-injection.yaml
#
kubectl get deploy,svc,ep my-user-gateway-injected -n istioinaction
4.5.3 Ingress gateway access logs 인그레스 게이트웨이 액세스 로그 (실습)
프록시에서 일반적인 기능은 처리하는 모든 요청을 기록하는 것이다. 이 액세스 로그는 문제 해결에 유용한다. 이스티오의 프록시(엔보이)도 액세스 로그를 만들 수 있다.
데모 설치 프로필에서는 인그레스 게이트웨이와 서비스 프록시가 액세스 로그를 표준 출력 스트림에 출력하도록 설정된다. 액세스 로그를 보려면 컨테이너 로그를 출력하기만 하면 된다.
위 명령은 인그레스 게이트웨이의 액세스 로그를 출력한다. 따라서 앞선 예제들에서 만들어낸 트래픽들의 기록을 볼 수 있다. 기본 프로필을 사용한 운영 환경 이스티오에서는 액세스 로깅이 비활성화돼 있다는 사실을 알면 놀랄 수도 있다.
# 반복 호출
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 webapp
webapp-7685bcb84-h5knf webapp 2025/04/14 09:28:40.248 [M] [router.go:1014] 172.18.0.1 - - [14/Apr/2025 09:28:40] "GET /api/catalog HTTP/1.1 200 0" 0.004840 curl/8.7.1
...
# 초기 부팅 로그 이외에 별다른 로그 출력이 없음
kubectl stern -n istioinaction -l app=webapp -c istio-proxy
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002358Z info FLAG: --concurrency="2"
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002374Z info FLAG: --domain="istioinaction.svc.cluster.local"
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002376Z info FLAG: --help="false"
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002377Z info FLAG: --log_as_json="false"
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002378Z info FLAG: --log_caller=""
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002379Z info FLAG: --log_output_level="default:info"
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002380Z info FLAG: --log_rotate=""
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002381Z info FLAG: --log_rotate_max_age="30"
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002382Z info FLAG: --log_rotate_max_backups="1000"
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002383Z info FLAG: --log_rotate_max_size="104857600"
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002384Z info FLAG: --log_stacktrace_level="default:none"
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002386Z info FLAG: --log_target="[stdout]"
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002387Z info FLAG: --meshConfig="./etc/istio/config/mesh"
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002388Z info FLAG: --outlierLogPath=""
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002389Z info FLAG: --proxyComponentLogLevel="misc:error"
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002390Z info FLAG: --proxyLogLevel="warning"
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002390Z info FLAG: --serviceCluster="istio-proxy"
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002391Z info FLAG: --stsPort="0"
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002392Z info FLAG: --templateFile=""
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002393Z info FLAG: --tokenManagerPlugin="GoogleTokenExchange"
webapp-7685bcb84-h5knf istio-proxy 2025-04-14T01:21:58.002395Z info FLAG: --vklog="0"
...
#
그러나 표준 출력 스트림으로 출력하도록 accessLogFile 속성을 변경해 이를 변경할 수 있다.
#
kubectl get cm -n istio-system istio -o yaml
data:
mesh: |-
defaultConfig:
discoveryAddress: istiod.istio-system.svc:15012
proxyMetadata: {}
tracing:
zipkin:
address: zipkin.istio-system:9411
enablePrometheusMerge: true
rootNamespace: istio-system
trustDomain: cluster.local
meshNetworks: 'networks: {}'
..
#
docker exec -it myk8s-control-plane bash
------------------------------------------
# 표준 출력 스트림으로 출력하도록 accessLogFile 속성을 변경
istioctl install --set meshConfig.accessLogFile=/dev/stdout
y 입력
exit
------------------------------------------
# configmap 에 mesh 바로 아래에 accessLogFile 부분 추가됨
kubectl get cm -n istio-system istio -o yaml
...
mesh: |-
accessLogFile: /dev/stdout
...
# 애플리케이션 호출에 대한 로그도 출력됨!
kubectl stern -n istioinaction -l app=webapp -c istio-proxy
webapp-7685bcb84-h5knf istio-proxy [2025-04-14T09:30:47.764Z] "GET /items HTTP/1.1" 200 - via_upstream - "-" 0 502 1 1 "172.18.0.1" "beegoServer" "4c10dba4-f49a-4b58-9805-ac30515dd417" "catalog.istioinaction:80" "10.10.0.8:3000" outbound|80||catalog.istioinaction.svc.cluster.local 10.10.0.9:60052 10.200.1.251:80 172.18.0.1:0 - default
webapp-7685bcb84-h5knf istio-proxy [2025-04-14T09:30:48.805Z] "GET /items HTTP/1.1" 200 - via_upstream - "-" 0 502 6 6 "172.18.0.1" "beegoServer" "7733f4d0-6e3a-4138-a126-fe25c30e51f4" "catalog.istioinaction:80" "10.10.0.8:3000" outbound|80||catalog.istioinaction.svc.cluster.local 10.10.0.9:60898 10.200.1.251:80 172.18.0.1:0 - default
...
액세스 로그는 기본적으로 꺼져 있는데, 운영 환경 클러스터에서 수백 또는 수천 개의 워크로드가 있고 각 워크로드가 많은 트래픽을 처리한다는 점을 고려하면 합리적이다. 또한 각 요청은 한 서비스에서 다른 서비스로 여러 홉을 이동하기 때문에 생성되는 액세스 로그량은 어떤 로깅 시스템에든 부담을 줄 수 있다.
더 나은 접근 방식은 관심 있는 워크로드에 대해서만 액세스 로그를 켜는 것이며, 이는 텔레메트리 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
4.5.4 Reducing gateway configuration 게이트웨이 설정 줄이기
기본적으로, 이스티오는 모든 프록시가 메시 내의 모든 서비스를 알도록 구성한다. 메시에 서비스가 많다면 데이터 플레인 프록시의 설정이 매우 커질 수 있다. 그리고 설정이 크면 리소스 증폭, 성능 문제, 확장성 문제로 이어질 수 있다.
이 문제를 해결하기 위해 데이터 플레인과 컨트롤 플레인 모두에게 설정을 최적화할 수 있다.
그러나 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 기능 플래그이다. - Docs
- If enabled, Pilot will send only clusters that referenced in gateway virtual services attached to gateway
이 플래그는 게이트웨이 프록시 설정 내에 있는 클러스터를 해당 게이트웨이에 적용한 VirtualService 에서 실제로 참조하는 클러스터로만 좁힌다.
Summary
- 인그레스 게이트웨이는 서비스 메시에 들어오는 트래픽을 세밀하게 제어합니다.
- 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.
'스터디 > Istio Hands-on Study' 카테고리의 다른 글
Istio Hands-on Study [1기] - 3주차 - Traffic control, Resilience - 5장 (0) | 2025.04.22 |
---|---|
Istio Hands-on Study [1기] - 2주차 - Envoy, Isto Gateway (4.2.3 이전) (1) | 2025.04.15 |
Istio Hands-on Study [1기] - 1주차 - Istio 소개, 첫걸음 (0) | 2025.04.13 |