CloudNet@ 가시다님이 진행하는 Istio 스터디 1기 - 5주차 정리 내용 입니다.
앞서 진행했던 주차를 보고 오시면 이해가 빠릅니다.
이번 글에서는,
- Istio에서 서비스 간 및 최종 사용자 인증은 어떻게 구현이 되는지?
- Istio에서 서비스 메시 내 서비스에 대한 접근 제어도 알아보겠습니다.
일단 Istio의 보안 기능에 대해 알아보기전, 보안주제에 대해 간략히 알아보겠습니다.
먼저 애플리케이션 네트워크 보안이 왜 필요한 지 알아보겠습니다.
✅ 애플리케이션 보안이란?
인가받지 않은 사용자가 오염시키거나 훔치거나 접근해서는 안되는 귀중한 애플리케이션 데이터를 보호하는 데 기여하는 모든 행동을 말합니다.
사용자 데이터를 지키려면 다음과 같은 사항이 필요합니다.
- 리소스 접근을 허가하기 전 사용자 인증 및 인가
- 데이터를 요청한 클라이언트로 가면서 여러 네트워크 장치를 거쳐가는 동안 데이터 도청을 방지하는 전송 중 데이터 암호화
이제 하나씩 자세히 살펴보겠습니다.
📌 서비스 간 인증
서비스가 안전하려면, 자신이 상호작용하는 서비스는 모두 인증을 해야 합니다.
즉, 확인할 수 있는 ID 문서를 제시한 후에만 다른 서비스를 신뢰할 수 있도록 해야합니다.
보통 해당 ID 문서는 신뢰할 수 있는 제 3자에게 확인을 합니다.
이번에는 Istio가 SPIFFE(Secure Production Identity Framework for Everyone) 프레임워크를 사용해 서비스들의 ID 발급을 자동화 하는 방법을 알아보겠습니다.
📌 최종 사용자 인증
최종 사용자 인증은 사용자의 개인 데이터를 저장하는 애플리케이션의 핵심입니다.
최종 사용자 인증 프로토콜은 여러 가지가 있지만, 대부분은 인증 서버로 리다이렉션 하는 것이 핵심 입니다.
사용자가 인증 서버에서 로그인을 성공하면, 사용자 정보를 담고 있는 자격 증명(HTTP 쿠키, JWT 등) 을 받습니다.
사용자는 인증을 위해 이 자격 증명을 서비스에 제시하여 자격 증명을 검증받습니다.
📌 인가
인가는 호출자가 인증된 후 진행됩니다.
호출자가 '누구' 인지 서버가 식별을 하고나면, 서버는 해당 ID가 '어떤' 작업을 수행할 수 있도록 허용돼 있는지 확인하고 그에 따라 승인하거나 거부합니다.
ex) 웹 어플리케이션에서 사용자가 로그인을 한 후에, 리소스를 생성, 조회, 업데이트, 삭제를 시도 할 때, 동작을 수행할 수 있는 권한이 있는지 판단하는 과정을 인가 라고 합니다.
Istio는 서비스 인증과 ID 모델을 기반으로 서비스 사이에 또는 최종 사용자와 서비스 사이에 세분화된 인가 기능을 제공합니다.
📌 모놀리스와 마이크로서비스의 보안 비교
모놀리스와 마이크로서비스 모두 최종 사용자 및 서비스 간 인증과 인가를 구현하는 것은 동일하지만,
마이크로서비스에는 보호해야하는, 네트워크를 오가는 커넥션과 요청이 훨씬 더 많습니다.
마이크로서비스 애플리케이션은 모놀리스 애플리케이션와 달리 아래 그림처럼 IP 주소가 정적으로 할당되는 것이 아닌 동적으로 할당됩니다.
또한 실행되는 애플리케이션들의 수명이 짧고, 같은 네트워크에서 실행되는 것이 아니라 여러 클라우드 프로바이더에 걸쳐 있거나 심지어 온프레미스에서도 실행될 수 있습니다.
위와 같은 문제를 해결하고, Istio는 SPIFFE(specification) 사양을 사용합니다.
SPIFFE는 분산 시스템에서 각 서비스에 보안 신원을 부여하기 위한 오픈 표준 프레임워크 입니다.
쉽게 말하자면, 마이크로서비스 환경에서 "누가 누구인지" 를 확인하고 보안 연결을 가능하게 해주는 신원 시스템 입니다.
📌 Istio가 SPIFFE를 구현하는 방법
SPIFFE ID는 RFC 3986 호환 URI로, spiffe://trust-domain/path 형식으로 구성됩니다.
- trust-domain 은 개인 또는 조직 같은 ID 발급자를 나타냅니다.
- path는 trust-domain 내에서 워크로드를 유일하게 식별합니다.
Istio에서 위 path는 특정 워크로드가 사용하는 서비스 어카운트 로 채웁니다.
그리고 SPIFFE ID는 SVID(Spiffe Verifiable Identity Document, SPIFFE 검증할 수 있는 ID 문서) 라고 하는 X.509 인증서로 인코딩되며, 이는 Istio의 컨트롤 플레인이 워크로드마다 만들어 냅니다.
그런 다음, 해당 인증서는 전송 데이트를 암호화함으로써 서비스 간 통신의 전송을 보호하는데 사용됩니다.
흐름을 요약하자면,
🔐 통신 흐름 요약
1. 파드가 생성되면 Istio의 sidecar가 함께 주입됨.
2. Envoy는 Istiod의 인증서 API를 통해 X.509 인증서(SVID)를 요청.
3. Istiod는 워크로드의 ServiceAccount, Namespace를 기반으로 SPIFFE ID를 생성.
4. Envoy는 해당 인증서를 저장하고, 이후 서비스 간 통신 시 사용.
5. 서로 통신하는 Envoy 간에는 mTLS가 설정되며, 상대방의 SPIFFE ID를 검증함.
6. AuthorizationPolicy나 PeerAuthentication 리소스를 이용해 ID 기반 인가 정책을 설정 가능.
📌 Istio 보안 요약
마지막으로 Istio 보안을 이해하기 위해 Istio가 정의한 커스텀 리소스로 프록시를 설정하는 서비스 메시 운영자의 관점으로 살펴보겠습니다.
위 그림은 PeerAuthentication, RequestAuthentication, AuthorizationPolicy 리소스가 어떻게 요청을 인증하도록 프록시를 구성하는지,
자격증명(SVID, JWT)에 인코딩된 정보가 어느 시점에 추출돼 필터 메타데이터로 저장되는지를 보여줍니다.
설명을 조금 덧붙이자면,
- PeerAuthentication:
- 서비스 간 트래픽을 인증하도록 프록시를 설정합니다.
- 인증에 성공하면, 자격 증명에 인코딩된 정보를 추출하여 요청 인가에 사용할 수 있도록 합니다. - RequestAuthentication:
- 프록시가 최종 사용자의 자격 증명을 발급 서버에 확인해 인증하도록 설정합니다.
- 인증에 성공하면, 자격 증명에 인코딩된 정보를 추출해 요청 인가에 사용할 수 있도록 합니다. - AuthorizationPolicy:
- 앞선 두 리소스에 따라 추출한 정보를 토대로 프록시가 요청을 인가하거나 거부하도록 구성합니다.
이제 실제로 Istio에서 리소스를 실행하고 알아보겠습니다.
📌 자동 상호 TLS
사이드카 프록시가 주입된 서비스 사이의 트래픽은 기본적으로 암호화되고 서로 인증합니다.
위 그림은 컨트롤 플레인에서 발급한 인증서를 사용해 서비스들이 서로 인증하고 트래픽을 암호화 하는 방식 을 나타냅니다.
이제 실습을 통해 좀 더 자세히 알아보겠습니다.
🔧 실습 환경 구성
$ git clone https://github.com/AcornPublishing/istio-in-action
$ kind create cluster --name myk8s --image kindest/node:v1.23.17 --config - <> /root/.bashrc
$ curl -s -L https://istio.io/downloadIstio | ISTIO_VERSION=$ISTIOV sh -
$ cp istio-$ISTIOV/bin/istioctl /usr/local/bin/istioctl
$ istioctl version --remote=false
$ istioctl install --set profile=demo --set values.global.proxy.privileged=true -y
$ kubectl apply -f istio-$ISTIOV/samples/addons
$ exit
---
$ kubectl create ns istioinaction
$ kubectl label namespace istioinaction istio-injection=enabled
$ kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 8080, "nodePort": 30000}]}}'
$ kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "NodePort", "ports": [{"port": 443, "targetPort": 8443, "nodePort": 30005}]}}'
$ kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec":{"externalTrafficPolicy": "Local"}}'
$ kubectl patch svc -n istio-system prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 30001}]}}'
$ kubectl patch svc -n istio-system grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "targetPort": 3000, "nodePort": 30002}]}}'
$ kubectl patch svc -n istio-system kiali -p '{"spec": {"type": "NodePort", "ports": [{"port": 20001, "targetPort": 20001, "nodePort": 30003}]}}'
$ kubectl patch svc -n istio-system tracing -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 16686, "nodePort": 30004}]}}'
기본 실습 환경 구성이 완료되었다면, 이제 mTLS 기능 실습을 해보겠습니다.
- mTLS 기능 실습을 위해 sleep, webapp, catalog 서비스 준비
- 여기서 sleep은 레거시 워크로드로 사이드카 프록시가 없어서 상호 인증을 할 수 없는 서비스 입니다.
🔧 catalog와 webapp 배포
$ kubectl apply -f services/catalog/kubernetes/catalog.yaml -n istioinaction
$ kubectl apply -f services/webapp/kubernetes/webapp.yaml -n istioinaction
🔧 webapp과 catalog의 gateway, virtualService 설정
$ kubectl apply -f services/webapp/istio/webapp-catalog-gw-vs.yaml -n istioinaction
🔧 default 네임스페이스에 sleep 앱 배포
# default 네임스페이스에는 사이드카 프록시를 추가하기 위한 label이 안 붙어있음
$ cat ch9/sleep.yaml
...
spec:
serviceAccountName: sleep
containers:
- name: sleep
image: governmentpaas/curl-ssl
command: ["/bin/sleep", "3650d"]
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /etc/sleep/tls
name: secret-volume
volumes:
- name: secret-volume
secret:
secretName: sleep-secret
optional: true
$ kubectl apply -f ch9/sleep.yaml -n default
🔧 설치 확인
$ kubectl get deploy,pod,sa,svc,ep
$ kubectl get deploy,svc -n istioinaction
$ kubectl get gw,vs -n istioinaction
🔧 통신 확인: 레거시 sleep 워크로드 -> webapp 워크로드로 평문 요청
🔧 요청 확인
$ kubectl exec deploy/sleep -c sleep -- curl -s webapp.istioinaction/api/catalog -o /dev/null -w "%{http_code}\n"
🔧 반복 요청
$ watch 'kubectl exec deploy/sleep -c sleep -- curl -s webapp.istioinaction/api/catalog -o /dev/null -w "%{http_code}\n"'
kiail Graph에서 결과를 보면 정상적으로 통신이 가고 있는 것을 확인할 수 있습니다.
그리고 요청자가 unknown 으로 나오는 이유는
sleep 파드에 사이드카 프록시가 존재하지 않아서 요청 보내는 출처를 Istio에서 확인 할 수 없어서 unknown 으로 나오게 됩니다.
Istio의 PeerAuthentication 리소스 이해하기
✅ PeerAuthentication 란?
Istio에서 서비스 간 통신에 대한 인증 방식을 설정하는 리소스입니다.예시를 들자면, mTLS(mutual TLS) 설정을 통해 Pod 간의 보안 통신을 어떻게 적용할지를 제어하는 기능입니다.
인증 모드는 두 가지가 있습니다.
- STRICT
- PERMISSIVE
또한, 상호 인증 모드는 다양한 범위에서 구성할 수 있습니다.
- 메시 범위 PeerAuthentication 정책은 서비스 메시의 모든 워크로드에 적용됩니다.
- 네임스페이스 범위 PeerAuthentication 정책은 네임스페이스 내 모든 워크로드에 적용됩니다.
- 워크로드 별 PeerAuthentication 정책은 정책에서 명시한 셀렉터에 부합하는 모든 워크로드에 적용됩니다.
이제 PeerAuthentication 리소스를 사용해보도록 하겠습니다.
메시의 보안을 향상시키기 위해 STRICT 상호 인증 모드를 강제하는 메시 범위 정책을 만들어서 평문 트래픽을 금지시켜보도록 하겠습니다.
여기서 필요한 조건이 두가지 있는데,
- 반드시 Istio를 설치한 네임스페이스에 적용하야하고,
- 이름은 "default" 여야 합니다.
🔧 PeerAuthentication 리소스 적용
$ cat ch9/meshwide-strict-peer-authn.yaml
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
name: "default" 메시 범위로 정책을 적용 시키려면 이름이 반드시 "default" 여야 합니다.
namespace: "istio-system" # Istio installation namespace
spec:
mtls:
mode: STRICT # mutual TLS mode
$ kubectl apply -f ch9/meshwide-strict-peer-authn.yaml -n istio-system
🔧 정책 적용되었는지 확인을 위한 트래픽 요청 실행
$ kubectl exec deploy/sleep -c sleep -- curl -s http://webapp.istioinaction/api/catalog -o /dev/null -w "%{http_code}\n"
결과
000
command terminated with exit code 56
🔧 로그 확인
$ kubectl logs -n istioinaction -l app=webapp -c istio-proxy -f-f
결과
# 결과를 보면, NR -> Non-Route. Envoy에서 라우팅까지 가지 못한 단계에서 발생한 에러라는 의미 입니다.
[2025-05-07T12:12:49.052Z] "- - -" 0 NR filter_chain_not_found - "-" 0 0 0 - "-" "-" "-" "-" "-" - - 10.10.0.6:8080 10.10.0.9:37888 - -
[2025-05-07T12:13:25.331Z] "- - -" 0 NR filter_chain_not_found - "-" 0 0 0 - "-" "-" "-" "-" "-" - - 10.10.0.6:8080 10.10.0.9:51132 - -
실제로 sleep 파드의 IP를 보면 10.10.0.9 이고,
webapp 파드의 IP는 10.10.0.6 입니다.
STRICT 모드 는 서비스 간 통신 시 무조건 mTLS(암호화 + 인증)를 적용하도록 강제 하는 설정입니다.
따라서 보안 측면에서는 이상적이지만, 진행 중인 프로젝트에서 갑작스럽게 보안 적용을 적용하는 것은 조금 무리입니다.
이럴 때는 PERMISSIVE 모드를 적용하는 것이 더 좋습니다.
PERMISSIVE 모드 는 Istio의 PeerAuthentication 리소스에서 mTLS(상호 TLS 인증)를 적용하되, 강제하지는 않는 설정 입니다.
즉, mTLS 통신도 허용하고, 평문(암호화되지 않은) HTTP 통신도 허용 합니다.
이제 네임스페이스 별 PERMISSIVE 모드로 적용해보겠습니다.
🔧 PERMISSIVE 모드 PeerAuthentication 리소스 적용
$ cat << EOF | kubectl apply -f -
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
name: "default"
namespace: "istioinaction" # 리소스 적용시킬 네임스페이스 지정
spec:
mtls:
mode: PERMISSIVE # PERMISSIVE 모드로 지정
EOF
🔧 PeerAuthentication 리소스 적용 확인
$ kubectl exec deploy/sleep -c sleep -- curl -s http://webapp.istioinaction/api/catalog -o /dev/null -w "%{http_code}\n"
결과
200
🔧 다음 실습을 위해 삭제
$ kubectl delete pa default -n istioinaction
이제 워크로드 별 PeerAuthentication 리소스를 적용시켜 보도록 하겠습니다.
webapp 서비스에만 적용시켜보도록 하겠습니다.
🔧 PeerAuthentication 리소스 적용
$ cat ch9/workload-permissive-peer-authn.yaml
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
name: "webapp" # 이름도 default에서 webapp으로 변경
namespace: "istioinaction"
spec:
selector:
matchLabels:
app: "webapp" # 레이블이 일치하는 워크로드만 PERMISSIVE로 동작
mtls:
mode: PERMISSIVE
$ kubectl apply -f ch9/workload-permissive-peer-authn.yaml
🔧 설정 적용되었는지 확인하기 위한 요청
$ kubectl exec deploy/sleep -c sleep -- curl -s http://webapp.istioinaction/api/catalog -o /dev/null -w "%{http_code}\n"
결과
200
🔧 webapp의 사이드카 프록시 로그 확인
$ kubectl logs -n istioinaction -l app=webapp -c istio-proxy -f
결과
[2025-05-07T12:45:40.875Z] "GET /api/catalog HTTP/1.1" 200 - via_upstream - "-" 0 357 16 16 "-" "curl/8.5.0" "04c5d35a-f6af-9b76-b402-9990cb78c598" "webapp.istioinaction" "10.10.0.6:8080" inbound|8080|| 127.0.0.6:36797 10.10.0.6:8080 10.10.0.9:39596 - defaul
🔧 catalog 로 요청
$ kubectl exec deploy/sleep -c sleep -- curl -s http://catalog.istioinaction/api/items -o /dev/null -w "%{http_code}\n"
결과
000
command terminated with exit code 56
🔧 catalog의 사이드카 프록시 로그 확인
$ kubectl logs -n istioinaction -l app=catalog -c istio-proxy -f
결과
[2025-05-07T12:47:55.025Z] "- - -" 0 NR filter_chain_not_found - "-" 0 0 0 - "-" "-" "-" "-" "-" - - 10.10.0.8:3000 10.10.0.9:35106 - -
이 처럼 PeerAuthentication 리소스에 webapp 만 PERMISSIVE 모드로 적용을 시켜주면,
webapp으로 요청을 보내면 정상적으로 응답을 하는데, catalog로 요청을 보내면 응답 결과가 없는 것을 확인할 수 있습니다.
우리는 앞서 STRICT, PERMISSIVE 두 가지 모드에 대해 알아보았습니다.
그러나 두 가지 모드가 더 존재합니다.
- UNSET: 부모의 PeerAuthentication 정책을 상속합니다.
- DISABLE: 트래픽을 터널링하지 않고 서비스로 직접 보냅니다.
이제 상호 TLS를 사용할 때 트래픽이 암호화 되는지 확인해보겠습니다.
Istio 프록시에는 tcpdump가 설치되어 있습니다. 해당 도구는 네트워크 인터페이스를 통과하는 네트워크 트래픽을 포착하고 분석 합니다.
tcpdump는 보안 때문에 권한 privileged permission이 필요한데, 기본적으로 해당 권한은 꺼져있습니다.
이 권한을 켜려면 istioctl로 속성 values.global.proxy.privileged=true 로 설정하여 Istio 설치를 업데이트 해야합니다.
저희는 demo 프로파일 컨트롤 플레인으로 배포하여 privileged 설정이 되어있습니다.
🔧 privileged 설정 확인
$ kubectl get istiooperator -n istio-system installed-state -o yaml
결과
proxy:
autoInject: enabled
clusterDomain: cluster.local
componentLogLevel: misc:error
enableCoreDump: false
excludeIPRanges: ""
excludeInboundPorts: ""
excludeOutboundPorts: ""
image: proxyv2
includeIPRanges: '*'
logLevel: warning
privileged: true
이제 파드 트래픽을 스니핑(Sniffing) 해보겠습니다.
🔧 패킷 모니터링 실행
# webapp의 사이드카 프록시에서 전체 패킷 내용 중 DNS 패킷을 제외한 패킷을 모두 캡처하도록 하는 명령어 입니다.
$ kubectl exec -it -n istioinaction deploy/webapp -c istio-proxy \
-- sudo tcpdump -l --immediate-mode -vv -s 0 '(((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0) and not (port 53)'
결과
tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
02:15:55.083178 IP (tos 0x0, ttl 64, id 53479, offset 0, flags [DF], proto TCP (6), length 168)
10.10.0.1.47464 > webapp-7685bcb84-vthpg.15021: Flags [P.], cksum 0x14bc (incorrect -> 0x428c), seq 611317287:611317403, ack 1941756628, win 502, options [nop,nop,TS val 1230365492 ecr 549265299], length 116
02:15:55.083991 IP (tos 0x0, ttl 64, id 51623, offset 0, flags [DF], proto TCP (6), length 195)
webapp-7685bcb84-vthpg.15021 > 10.10.0.1.47464: Flags [P.], cksum 0x14d7 (incorrect -> 0x6da2), seq 1:144, ack 116, win 509, options [nop,nop,TS val 549265300 ecr 1230365492], length 143
02:15:57.083470 IP (tos 0x0, ttl 64, id 64559, offset 0, flags [DF], proto TCP (6), length 168)
🔧 sleep 파드 -> webapp 파드로 요청
$ kubectl exec deploy/sleep -c sleep -- curl -s webapp.istioinaction/api/catalog -o /dev/null -w "%{http_code}\n"
🔧 sleep -> webapp 요청
결과
10-10-0-14.sleep.default.svc.cluster.local.45402 > webapp-7685bcb84-vthpg.http-alt: Flags [P.], cksum 0x14b3 (incorrect -> 0x12a0), seq 1669066549:1669066643, ack 702220574, win 502, options [nop,nop,TS val 2301065920 ecr 1326270720], length 94: HTTP, length: 94
webapp-7685bcb84-vthpg.http-alt > 10-10-0-14.sleep.default.svc.cluster.local.45402: Flags [P.], cksum 0x16b7 (incorrect -> 0xb656), seq 1:611, ack 94, win 509, options [nop,nop,TS val 1326270726 ecr 2301065920], length 610: HTTP, length: 610
🔧 webapp -> catalog 응답
결과
04:12:06.544469 IP (tos 0x0, ttl 64, id 22759, offset 0, flags [DF], proto TCP (6), length 2233)
webapp-7685bcb84-vthpg.47912 > 10-10-0-12.catalog.istioinaction.svc.cluster.local.3000: Flags [P.], cksum 0x1cd8 (incorrect -> 0x70bc), seq 1384690957:1384693138, ack 1066693404, win 502, options [nop,nop,TS val 1696099257 ecr 3256812525], length 2181
🔧 catalog -> webapp 응답
결과
04:12:06.560079 IP (tos 0x0, ttl 63, id 64145, offset 0, flags [DF], proto TCP (6), length 5502)
10-10-0-12.catalog.istioinaction.svc.cluster.local.3000 > webapp-7685bcb84-vthpg.47912: Flags [P.], cksum 0x299d (incorrect -> 0xb7f8), seq 219:5669, ack 3497, win 501, options [nop,nop,TS val 3256812541 ecr 1696099259], length 5450
🔧 webapp -> sleep 응답
결과
04:12:06.561872 IP (tos 0x0, ttl 64, id 50031, offset 0, flags [DF], proto TCP (6), length 663)
webapp-7685bcb84-vthpg.http-alt > 10-10-0-14.sleep.default.svc.cluster.local.34792: Flags [P.], cksum 0x16b8 (incorrect -> 0x8b26), seq 1:612, ack 94, win 509, options [nop,nop,TS val 1332485093 ecr 2307280269], length 611: HTTP, length: 611
HTTP/1.1 200 OK
content-length: 357
content-type: application/json; charset=utf-8
date: Thu, 08 May 2025 04:12:06 GMT
x-envoy-upstream-service-time: 21
server: istio-envoy
x-envoy-decorator-operation: webapp.istioinaction.svc.cluster.local:80/*
[{"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"}] [|http]
이제 발급된 인증서가 유효한 SVID 문서인지, SPIFFE ID가 인코딩 되어있는지, 그 ID가 워크로드 서비스 어카운트와 일치하는지 확인해보겠습니다.
🔧 webapp의 사이드카 프록시에서 catalog 서비스로 연결하여 TLS Handshake 및 인증서 체인 출력 후 사람이 읽을 수 있는 형식으로 출력
$ kubectl -n istioinaction exec deploy/webapp -c istio-proxy \
-- openssl s_client -showcerts \
-connect catalog.istioinaction.svc.cluster.local:80 \
-CAfile /var/run/secrets/istio/root-cert.pem | \
openssl x509 -in /dev/stdin -text -noout
결과
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
3e:20:ab:e6:06:ec:47:0c:7d:25:6c:a0:08:90:15:8e
Signature Algorithm: sha256WithRSAEncryption
Issuer: O = cluster.local # 클러스터 도메인 명
Validity # 유효기간
Not Before: May 8 01:02:20 2025 GMT
Not After : May 9 01:04:20 2025 GMT
Subject:
....
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage: # 사용처
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Authority Key Identifier:
AC:82:14:B3:EB:F6:03:CE:E7:50:11:2B:AA:8F:27:23:CA:AC:6B:D1
X509v3 Subject Alternative Name: critical
URI:spiffe://cluster.local/ns/istioinaction/sa/catalog # 서비스계정: catalog, 네임스페이스: istioinaction
....
이제 루트 인증서 서명 확인도 해보겠습니다.
🔧 webapp의 사이드카 프록시 쉘에 접속
$ kubectl -n istioinaction exec -it deploy/webapp -c istio-proxy -- /bin/bash
---
🔧 루트 인증서 검증
$ openssl verify -CAfile /var/run/secrets/istio/root-cert.pem \
<(openssl s_client -connect \
catalog.istioinaction.svc.cluster.local:80 -showcerts 2>/dev/null)
결과
/dev/fd/63: OK
$ exit
---
위 실습을 통해 Istio 서비스 메시 내부의 통신은 실제로 mTLS에 의해 암호화 되어 전달되고 있음을 확인할 수 있습니다.
다음 글에서는,
- 서비스 간 트래픽 인가
- 최종 사용자 인증 및 인가
- 커스텀 외부 인가 서비스와 통합하기
대해 알아보도록 하겠습니다.
감사합니다.
'스터디 > Istio' 카테고리의 다른 글
Istio 스터디 5주차 - <마이크로서비스 통신 보호 2부> (0) | 2025.05.11 |
---|---|
Istio 스터디 4주차 - <Observability 시각화> (1) | 2025.05.03 |
Istio 스터디 4주차 - <Observability> (0) | 2025.04.30 |
Istio 스터디 3주차 - <Resilience> (0) | 2025.04.25 |
Istio 스터디 3주차 - <Traffic Control> (0) | 2025.04.23 |