LabHub
시작하기
배우기 러닝패스 코스

Istio 실측 실험실

쿠버네티스 밖 머신에 같은 신원을 준다

LabHub 에서 이어서 보기

목표

같은 VM 안의 네트워크 네임스페이스로 만든 '메시 밖 머신' 에 VM 용 사이드카를 띄워 WorkloadGroup·WorkloadEntry 로 메시에 넣고, 양쪽 방향의 mTLS 와 STRICT·인가 정책이 파드와 똑같이 걸리는 것을 확인한다.

왜 중요한가

컨테이너로 옮기지 못한 머신은 메시의 예외가 되기 쉽고, 예외는 PERMISSIVE 나 넓은 허용 규칙으로 이어져 보안의 구멍이 된다. 그 머신에 같은 사이드카와 같은 신원을 주면 예외 없이 같은 정책을 걸 수 있다. 절차가 길고 이름 풀이·토큰·가로채기 규칙에서 막히기 쉬워서, 한 번 끝까지 해 보는 것이 가장 빠른 공부다.

단계

  1. kubectl apply -f /opt/fixtures/istlab/vmworkload-app.yaml 로 재료를 올리고 파드가 준비될 때까지 기다리세요. 이 VM 에는 네트워크 네임스페이스 legacy(192.168.77.2)가 있고 그 안에서 앱이 8080 으로 돕니다. /root/istlab-vm/01-outside.txt 에 세 줄을 적으세요 — client 에서 http://192.168.77.2:8080/ 의 상태 코드 from_client=, 메시 밖 probe 에서 같은 요청의 상태 코드 from_outside=, istioctl proxy-status 에 legacy 가 보이면 yes 아니면 no 인 in_mesh=.
  2. /root/istlab-vm/vmns.yaml 에 네 리소스를 적어 적용하세요 — 네임스페이스 vmns(주입 라벨), 서비스어카운트 legacy-sa, WorkloadGroup legacy(메타데이터 라벨 app: legacy, 템플릿의 서비스어카운트 legacy-sa, 포트 http: 8080), 그리고 셀렉터 app: legacy 로 8080 을 내놓는 Service legacy(포트 이름 http).
  3. kubectl -n vmns get workloadgroup legacy -o yaml/root/istlab-vm/wg.yaml 에 저장하고, istioctl x workload entry configure -f /root/istlab-vm/wg.yaml -o /root/istlab-vm/files --clusterID Kubernetes --ingressIP <istiod 서비스의 ClusterIP> --internalIP 192.168.77.2 로 VM 용 파일을 만드세요. /root/istlab-vm/filescluster.env·istio-token·mesh.yaml·root-cert.pem·hosts 가 생겨야 합니다.
  4. 03단계의 파일을 공식 문서의 자리에 놓고(root-cert.pem/etc/certs/root-cert.pem, istio-token/var/run/secrets/tokens/istio-token, cluster.env/var/lib/istio/envoy/cluster.env, mesh.yaml/etc/istio/config/mesh, hosts 의 줄은 네임스페이스용 /etc/netns/legacy/hosts 에 덧붙임), 소유자를 istio-proxy 로 바꾼 뒤 네임스페이스 안에서 /usr/local/bin/istio-start.sh 를 띄우세요(작업 디렉터리 /, POD_NAME=legacy-vm). istioctl proxy-statuslegacy-vm.vmns 가 보여야 하고, /root/istlab-vm/04-iptables.txtnetns_backend=(네임스페이스 안에서 ISTIO 규칙이 든 쪽: legacy 또는 nft)과 host_istio_rules=(호스트의 nat 표 — nft·legacy 둘 다 — 에 있는 ISTIO 규칙 수) 두 줄을 적으세요.
  5. /root/istlab-vm/workloadentry.yamlWorkloadEntry legacy-vm(네임스페이스 vmns, 주소 192.168.77.2, 라벨 app: legacy, 서비스어카운트 legacy-sa)를 적어 적용하세요. 적용 뒤 client 에서 http://legacy.vmns:8080/ 이 본문 legacy-vm 과 200 을 돌려줘야 합니다.
  6. 네임스페이스 안에서 x-request-id 를 붙여 http://web.shop/ 을 부르고, 그 요청을 받은 web 사이드카의 접근 로그 한 줄을 그대로 /root/istlab-vm/06-from-vm.log 에 저장하세요.
  7. /root/istlab-vm/secure.yaml 에 두 리소스를 적어 적용하세요 — vmnsPeerAuthentication strict(STRICT)와 AuthorizationPolicy legacy-only-client(셀렉터 app: legacy, ALLOW, 주체 cluster.local/ns/shop/sa/client). 적용 뒤 client 는 200, other 의 intruder 는 403, 메시 밖 probe 가 192.168.77.2:8080 을 평문으로 부르면 연결이 끊겨야 합니다.
  8. /root/istlab-vm/08-report.md 에 다섯 줄 — vm_identity=(VM 사이드카가 받은 인증서의 SPIFFE URI), netns_iptables_backend=·host_istio_rules=(4단계), plain_from_outside=(지금 probe 의 평문 요청이 통하면 allowed, 끊기면 rejected), intruder=(지금 intruder 의 상태 코드) — 을 적고 그 아래 배운 것을 네 줄 이상 적으세요.

참고

메시 밖 머신은 지금 어떻게 보이나

kubectl apply -f /opt/fixtures/istlab/vmworkload-app.yaml 로 재료를 올리고 파드가 준비될 때까지 기다리세요. 이 VM 에는 네트워크 네임스페이스 legacy(192.168.77.2)가 있고 그 안에서 앱이 8080 으로 돕니다. /root/istlab-vm/01-outside.txt 에 세 줄을 적으세요 — client 에서 http://192.168.77.2:8080/ 의 상태 코드 from_client=, 메시 밖 probe 에서 같은 요청의 상태 코드 from_outside=, istioctl proxy-status 에 legacy 가 보이면 yes 아니면 no 인 in_mesh=.

네트워크 네임스페이스는 커널이 따로 주는 네트워크 스택입니다 — 주소·라우팅 표·iptables 가 전부 따로라, 같은 VM 안에 있어도 '다른 기계' 처럼 행동합니다. 호스트와는 veth 쌍(192.168.77.1 ↔ 192.168.77.2)으로 이어져 있고, 파드에서 그 주소로 가는 트래픽은 호스트가 라우팅합니다. 안을 들여다볼 때는 ip netns exec legacy <명령> 을 씁니다. 지금 이 머신은 메시가 모르는 주소라 client 의 사이드카는 그냥 흘려보냅니다.

VM 을 위한 틀 — WorkloadGroup 과 서비스

/root/istlab-vm/vmns.yaml 에 네 리소스를 적어 적용하세요 — 네임스페이스 vmns(주입 라벨), 서비스어카운트 legacy-sa, WorkloadGroup legacy(메타데이터 라벨 app: legacy, 템플릿의 서비스어카운트 legacy-sa, 포트 http: 8080), 그리고 셀렉터 app: legacy 로 8080 을 내놓는 Service legacy(포트 이름 http).

WorkloadGroup 은 VM 을 위한 파드 템플릿입니다 — 라벨·서비스어카운트·포트처럼 '이런 머신들이 이런 신원으로 이 포트를 연다' 를 적습니다. 쿠버네티스 서비스의 셀렉터는 파드뿐 아니라 Istio 의 WorkloadEntry 도 고르므로, VM 을 기존 서비스 이름 뒤에 둘 수 있습니다. 아직 VM 한 대(WorkloadEntry)는 없으므로 서비스의 엔드포인트는 비어 있습니다.

VM 에 건넬 파일을 만든다

kubectl -n vmns get workloadgroup legacy -o yaml/root/istlab-vm/wg.yaml 에 저장하고, istioctl x workload entry configure -f /root/istlab-vm/wg.yaml -o /root/istlab-vm/files --clusterID Kubernetes --ingressIP <istiod 서비스의 ClusterIP> --internalIP 192.168.77.2 로 VM 용 파일을 만드세요. /root/istlab-vm/filescluster.env·istio-token·mesh.yaml·root-cert.pem·hosts 가 생겨야 합니다.

VM 의 사이드카가 알아야 할 것은 다섯입니다 — 자기가 누구인지(cluster.env 의 네임스페이스·서비스어카운트·라벨), 처음 인증서를 받을 때 내밀 토큰(istio-token, 서비스어카운트 토큰), 메시 설정(mesh.yaml), 믿을 루트(root-cert.pem), istiod 를 찾을 주소(hosts). 여러 네트워크에 걸친 설치라면 동서 게이트웨이의 주소를 주지만, 이 VM 에서는 네트워크 네임스페이스가 호스트의 kube-proxy 규칙을 타고 istiod 의 ClusterIP 에 바로 닿습니다. istiod 주소는 kubectl -n istio-system get svc istiod -o jsonpath='{.spec.clusterIP}'.

메시 밖 머신에서 사이드카를 띄운다

03단계의 파일을 공식 문서의 자리에 놓고(root-cert.pem/etc/certs/root-cert.pem, istio-token/var/run/secrets/tokens/istio-token, cluster.env/var/lib/istio/envoy/cluster.env, mesh.yaml/etc/istio/config/mesh, hosts 의 줄은 네임스페이스용 /etc/netns/legacy/hosts 에 덧붙임), 소유자를 istio-proxy 로 바꾼 뒤 네임스페이스 안에서 /usr/local/bin/istio-start.sh 를 띄우세요(작업 디렉터리 /, POD_NAME=legacy-vm). istioctl proxy-statuslegacy-vm.vmns 가 보여야 하고, /root/istlab-vm/04-iptables.txtnetns_backend=(네임스페이스 안에서 ISTIO 규칙이 든 쪽: legacy 또는 nft)과 host_istio_rules=(호스트의 nat 표 — nft·legacy 둘 다 — 에 있는 ISTIO 규칙 수) 두 줄을 적으세요.

istio-sidecar.deb(조리법이 이미 깔아 둠)은 pilot-agent·envoy·istio-start.sh 를 넣습니다. istio-start.sh 는 iptables 로 가로채기 규칙을 심고 istio-proxy 사용자로 pilot-agent 를 띄웁니다. 이것을 ip netns exec legacy setsid --fork nohup env POD_NAME=legacy-vm /usr/local/bin/istio-start.sh > 로그 2>&1 </dev/null 로 네임스페이스 안에서 돌리면, 규칙이 그 네임스페이스의 iptables 에만 들어갑니다. 스크립트가 ./var/lib/istio 같은 상대 경로를 쓰므로 cd / 뒤에 띄우세요. 규칙은 ip netns exec legacy iptables-legacy -t nat -Siptables-nft 로, 호스트 쪽은 네임스페이스 없이 봅니다. 로그는 /var/log/istio/istio.log 입니다.

VM 한 대를 서비스 뒤에 넣는다 — WorkloadEntry

/root/istlab-vm/workloadentry.yamlWorkloadEntry legacy-vm(네임스페이스 vmns, 주소 192.168.77.2, 라벨 app: legacy, 서비스어카운트 legacy-sa)를 적어 적용하세요. 적용 뒤 client 에서 http://legacy.vmns:8080/ 이 본문 legacy-vm 과 200 을 돌려줘야 합니다.

WorkloadEntry 는 VM 한 대를 파드처럼 나타내는 리소스입니다. 라벨이 서비스 legacy 의 셀렉터와 맞으므로, istiod 는 이 주소를 그 서비스의 엔드포인트로 사이드카들에게 내려보냅니다. client 의 사이드카는 VM 의 사이드카와 mTLS 로 통신하고, 들어가는 쪽은 네임스페이스 안의 iptables 가 8080 을 VM 사이드카로 돌립니다. istioctl proxy-config endpoints client.shop --cluster 'outbound|8080||legacy.vmns.svc.cluster.local' 에 192.168.77.2 가 보여야 합니다. 자동 등록은 이 설치에서 꺼져 있어 손으로 만듭니다.

VM 에서 메시 안 서비스를 이름으로 부른다

네임스페이스 안에서 x-request-id 를 붙여 http://web.shop/ 을 부르고, 그 요청을 받은 web 사이드카의 접근 로그 한 줄을 그대로 /root/istlab-vm/06-from-vm.log 에 저장하세요.

VM 의 사이드카도 DNS 프록시를 켜 두어서(cluster.env 의 ISTIO_META_DNS_CAPTURE) 클러스터 서비스 이름을 풀고, 나가는 요청은 사이드카가 받아 mTLS 로 보냅니다. web 쪽 로그에서 그 요청의 출발지가 192.168.77.2 이고 SNI 가 outbound_.80_._.web.shop.svc.cluster.local 인지 보세요 — 평문이 아니라 메시 안의 연결이라는 증거입니다. 부를 때는 ip netns exec legacy curl … 입니다.

VM 앞에도 mTLS 와 인가를 건다

/root/istlab-vm/secure.yaml 에 두 리소스를 적어 적용하세요 — vmnsPeerAuthentication strict(STRICT)와 AuthorizationPolicy legacy-only-client(셀렉터 app: legacy, ALLOW, 주체 cluster.local/ns/shop/sa/client). 적용 뒤 client 는 200, other 의 intruder 는 403, 메시 밖 probe 가 192.168.77.2:8080 을 평문으로 부르면 연결이 끊겨야 합니다.

PeerAuthentication 과 AuthorizationPolicy 는 파드든 VM 이든 워크로드 라벨로 고릅니다. VM 의 사이드카가 cluster.env 의 라벨(app: legacy)을 들고 istiod 에 붙었으므로, 같은 정책이 VM 의 사이드카에 내려갑니다. 메시 밖에서 평문으로 들어오는 요청은 네임스페이스 안의 iptables 가 사이드카로 돌리고, STRICT 인 사이드카가 그 연결을 끊습니다. 정책이 퍼지는 데 몇 초가 걸립니다.

메시 밖 머신이 메시 안으로 들어온 길을 적는다

/root/istlab-vm/08-report.md 에 다섯 줄 — vm_identity=(VM 사이드카가 받은 인증서의 SPIFFE URI), netns_iptables_backend=·host_istio_rules=(4단계), plain_from_outside=(지금 probe 의 평문 요청이 통하면 allowed, 끊기면 rejected), intruder=(지금 intruder 의 상태 코드) — 을 적고 그 아래 배운 것을 네 줄 이상 적으세요.

VM 사이드카의 인증서는 네임스페이스 안에서 Envoy 관리 포트로 볼 수 있습니다 — ip netns exec legacy curl -s 'localhost:15000/config_dump?resource=dynamic_active_secrets'default 인증서를 base64 로 풀어 openssl x509 -noout -ext subjectAltName 으로 읽습니다(파드가 아니라서 istioctl proxy-config 는 이 프록시에 붙지 못합니다).