LabHub
Get started
배우기 러닝패스 코스

Istio Field Lab

We Added a Waypoint and Got 503

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

k3s 위의 진짜 앰비언트 메시에서 ztunnel 이 강제하는 L4 와 waypoint 가 강제하는 L7 을 나눠 겪고, waypoint 를 붙일 때 함께 고쳐야 하는 것을 요청과 로그로 확인한다.

왜 중요한가

앰비언트는 사이드카를 없애 가볍지만, 정책과 라우팅이 두 층(ztunnel·waypoint)으로 나뉜다. 어느 층이 무엇을 보는지 모르면 HTTP 규칙이 조용히 빠지고, waypoint 를 붙이는 순간 멀쩡하던 트래픽이 끊기며, 파드 IP 로 오는 요청이 L7 정책을 우회한다. 셋 다 매니페스트만으로는 보이지 않아서 진짜 메시에서 겪어 봐야 남는다.

단계

  1. kubectl apply -f /opt/fixtures/istlab/ambient-app.yaml 로 재료를 올리고 파드가 준비될 때까지 기다린 뒤, 네임스페이스 shopistio.io/dataplane-mode=ambient 라벨을 붙이세요(파드를 다시 만들지 않습니다). 그다음 /root/istlab-ambient/01-enroll.txtweb_containers=(web-v1 파드의 컨테이너 이름을 쉼표로)와 protocol=(istioctl ztunnel-config workloads 에서 shop 파드들의 PROTOCOL 칸) 두 줄을 적으세요.
  2. client 에서 http://web/ 을 한 번 부르고, 그 연결을 기록한 ztunnel 접근 로그 줄(메시지가 connection complete 이고 src.identity 가 client, dst.identity 가 web 인 줄) 하나를 그대로 /root/istlab-ambient/02-ztunnel.log 에 저장하세요.
  3. /root/istlab-ambient/web-l4.yamlAuthorizationPolicy web-l4(네임스페이스 shop, 셀렉터 app: web, ALLOW, 주체 cluster.local/ns/shop/sa/client)를 적어 적용하세요. 적용 뒤 client 와 outside 의 stranger 에서 각각 http://web.shop/ 을 부르고 /root/istlab-ambient/03-l4.txtclient=(상태 코드)와 stranger_exit=(stranger 쪽 curl 의 종료 코드) 두 줄을 적으세요.
  4. /root/istlab-ambient/l7-wrong.yamlAuthorizationPolicy web-get-only-l4(셀렉터 app: web, ALLOW, 주체 client, 메서드 GET)를 적어 적용하고, 그 정책의 status.conditions 에서 ZtunnelAccepted 조건의 reason/root/istlab-ambient/04-l7.txtstatus_reason= 으로, client 의 POST 요청 상태 코드를 post_code= 로 적으세요. 기록한 뒤 이 정책을 지웁니다.
  5. istioctl waypoint apply -n shop --enroll-namespace --wait 로 shop 에 waypoint 를 붙이세요. 그 직후 client 의 http://web/ 상태 코드를 /root/istlab-ambient/05-waypoint.txtcode_after_waypoint= 로 적고, 원인을 고치세요 — /root/istlab-ambient/web-l4.yaml 의 허용 주체를 waypoint 의 신원 cluster.local/ns/shop/sa/waypoint 하나로 바꿔 다시 적용합니다. 고친 뒤 client 의 http://web/ 은 200, client 가 web-v1 파드 IP 로 직접 부르면 연결이 끊겨야 합니다.
  6. /root/istlab-ambient/web-get-only.yamlAuthorizationPolicy web-get-only 를 적어 적용하세요 — targetRefs 로 서비스 web(group "", kind Service)을 가리키고, ALLOW, 주체 cluster.local/ns/shop/sa/client, 메서드 GET. 적용 뒤 client 의 GET 은 200, POST 는 403 이어야 합니다.
  7. /root/istlab-ambient/httproute.yamlHTTPRoute web 을 적어 적용하세요 — 부모는 서비스 web(group "", kind Service, 포트 80), 규칙 둘: 헤더 x-canary: yesweb-v2, 그 밖에는 web-v1. 적용 뒤 client 의 x-canary: yes 요청은 v2, 헤더 없는 요청은 늘 v1 이어야 합니다.
  8. /root/istlab-ambient/08-report.md 에 여섯 줄 — protocol=(1단계), l7_without_waypoint=(4단계에서 GET 규칙이 강제됐으면 enforced, 빠졌으면 ignored), broke_with_waypoint=(5단계 code_after_waypoint), l4_allowed_principal=(지금 web-l4 가 허용하는 주체), post_via_waypoint=(지금 client 의 POST 상태 코드), direct_pod_ip=(지금 client 가 파드 IP 로 직접 부르면 allowed 또는 rejected) — 을 적고 그 아래 배운 것을 네 줄 이상 적으세요.

참고

라벨 하나로 메시에 넣는다 — 재시작 없이

kubectl apply -f /opt/fixtures/istlab/ambient-app.yaml 로 재료를 올리고 파드가 준비될 때까지 기다린 뒤, 네임스페이스 shopistio.io/dataplane-mode=ambient 라벨을 붙이세요(파드를 다시 만들지 않습니다). 그다음 /root/istlab-ambient/01-enroll.txtweb_containers=(web-v1 파드의 컨테이너 이름을 쉼표로)와 protocol=(istioctl ztunnel-config workloads 에서 shop 파드들의 PROTOCOL 칸) 두 줄을 적으세요.

앰비언트에서는 istio-cni 노드 에이전트가 파드의 네트워크 네임스페이스 안에 가로채기 규칙을 심고, 노드마다 하나 있는 ztunnel 이 그 트래픽을 받습니다. 사이드카를 주입하지 않으니 파드를 다시 만들 필요가 없습니다. 편입된 파드는 애너테이션 ambient.istio.io/redirection: enabled 가 붙고, ztunnel 이 아는 워크로드 목록에서 프로토콜이 HBONE 으로 바뀝니다. 메시 밖 stranger 는 TCP 로 남습니다.

ztunnel 이 본 두 신원

client 에서 http://web/ 을 한 번 부르고, 그 연결을 기록한 ztunnel 접근 로그 줄(메시지가 connection complete 이고 src.identity 가 client, dst.identity 가 web 인 줄) 하나를 그대로 /root/istlab-ambient/02-ztunnel.log 에 저장하세요.

앰비언트의 mTLS 는 ztunnel 끼리 HBONE(HTTP CONNECT 위의 mTLS 터널, 포트 15008)으로 맺습니다. ztunnel 은 L4 프록시라 요청 경로나 메서드는 모르지만 양쪽 워크로드의 SPIFFE 신원은 압니다. 로그는 kubectl -n istio-system logs ds/ztunnel 로 보고, 한 연결이 출발 쪽과 도착 쪽에서 한 줄씩 남을 수 있습니다. dst.hbone_addr 가 붙은 줄이 HBONE 으로 들어간 연결입니다.

ztunnel 이 강제하는 L4 정책

/root/istlab-ambient/web-l4.yamlAuthorizationPolicy web-l4(네임스페이스 shop, 셀렉터 app: web, ALLOW, 주체 cluster.local/ns/shop/sa/client)를 적어 적용하세요. 적용 뒤 client 와 outside 의 stranger 에서 각각 http://web.shop/ 을 부르고 /root/istlab-ambient/03-l4.txtclient=(상태 코드)와 stranger_exit=(stranger 쪽 curl 의 종료 코드) 두 줄을 적으세요.

셀렉터로 붙인 정책은 그 파드의 ztunnel 이 강제합니다. ztunnel 은 연결을 받는 순간 출발지 신원을 보고 허용 여부를 정하므로, 거절은 HTTP 403 이 아니라 연결 끊김(curl 종료 코드 56)으로 나타납니다. 메시 밖의 stranger 는 신원이 없어 어떤 주체 규칙에도 맞지 않습니다. 종료 코드는 …; echo $? 로 봅니다.

waypoint 없이 쓴 HTTP 규칙은 어떻게 되나

/root/istlab-ambient/l7-wrong.yamlAuthorizationPolicy web-get-only-l4(셀렉터 app: web, ALLOW, 주체 client, 메서드 GET)를 적어 적용하고, 그 정책의 status.conditions 에서 ZtunnelAccepted 조건의 reason/root/istlab-ambient/04-l7.txtstatus_reason= 으로, client 의 POST 요청 상태 코드를 post_code= 로 적으세요. 기록한 뒤 이 정책을 지웁니다.

ztunnel 은 HTTP 를 해석하지 않습니다. 메서드·경로 같은 조건이 든 규칙을 셀렉터 정책으로 주면 istiod 는 그 규칙을 빼고 ztunnel 에 내려보내며, 정책의 상태에 그 사실을 적어 둡니다. ALLOW 정책끼리는 '하나라도 맞으면 허용' 이라, 이미 있는 web-l4 가 client 를 허용하고 있으면 POST 도 통과합니다 — GET 만 허용한다고 적었는데 POST 가 되는 것입니다. 상태는 kubectl -n shop get authorizationpolicy web-get-only-l4 -o yaml 로 봅니다.

waypoint 를 붙이자 멀쩡하던 요청이 503

istioctl waypoint apply -n shop --enroll-namespace --wait 로 shop 에 waypoint 를 붙이세요. 그 직후 client 의 http://web/ 상태 코드를 /root/istlab-ambient/05-waypoint.txtcode_after_waypoint= 로 적고, 원인을 고치세요 — /root/istlab-ambient/web-l4.yaml 의 허용 주체를 waypoint 의 신원 cluster.local/ns/shop/sa/waypoint 하나로 바꿔 다시 적용합니다. 고친 뒤 client 의 http://web/ 은 200, client 가 web-v1 파드 IP 로 직접 부르면 연결이 끊겨야 합니다.

waypoint 가 생기면 서비스로 가는 요청은 client 의 ztunnel → waypoint → web 의 ztunnel 순으로 갑니다. 그래서 web 의 ztunnel 이 보는 출발지는 client 가 아니라 waypoint 입니다. client 만 허용하던 L4 정책이 그 연결을 끊고, waypoint 는 503 을 돌려줍니다(waypoint 로그의 tunnel_response:401). waypoint 신원만 허용하면 서비스로 오는 길은 열리고, waypoint 를 거치지 않는 길(파드 IP 로 직접)은 닫힙니다 — 서비스용 waypoint 는 파드 IP 로 온 요청을 거치지 않기 때문에, 이렇게 닫아야 7단계의 L7 정책을 우회하지 못합니다.

HTTP 규칙은 waypoint 에 건다

/root/istlab-ambient/web-get-only.yamlAuthorizationPolicy web-get-only 를 적어 적용하세요 — targetRefs 로 서비스 web(group "", kind Service)을 가리키고, ALLOW, 주체 cluster.local/ns/shop/sa/client, 메서드 GET. 적용 뒤 client 의 GET 은 200, POST 는 403 이어야 합니다.

waypoint 는 Envoy 라 HTTP 를 해석합니다. 정책을 waypoint 에 붙이는 방법은 셀렉터가 아니라 targetRefs 입니다 — 서비스를 가리키면 그 서비스로 가는 요청을 처리하는 waypoint 가 강제합니다. waypoint 에서 보는 출발지는 client 자신이므로 주체는 client 로 적습니다. 거절은 이번에는 연결 끊김이 아니라 HTTP 403 (RBAC: access denied)입니다.

waypoint 가 라우팅도 맡는다 — HTTPRoute

/root/istlab-ambient/httproute.yamlHTTPRoute web 을 적어 적용하세요 — 부모는 서비스 web(group "", kind Service, 포트 80), 규칙 둘: 헤더 x-canary: yesweb-v2, 그 밖에는 web-v1. 적용 뒤 client 의 x-canary: yes 요청은 v2, 헤더 없는 요청은 늘 v1 이어야 합니다.

앰비언트에서는 메시 안 라우팅도 Gateway API 로 적습니다. 부모가 Gateway 가 아니라 서비스라는 점이 인그레스와 다릅니다(GAMMA). 이 라우트를 실제로 처리하는 것은 web 의 waypoint 라서, waypoint 가 없으면 라우트가 적용되지 않습니다. 붙었는지는 HTTPRoute 상태의 ResolvedWaypoints 조건으로 봅니다.

L4 와 L7 을 누가 맡는지 정리한다

/root/istlab-ambient/08-report.md 에 여섯 줄 — protocol=(1단계), l7_without_waypoint=(4단계에서 GET 규칙이 강제됐으면 enforced, 빠졌으면 ignored), broke_with_waypoint=(5단계 code_after_waypoint), l4_allowed_principal=(지금 web-l4 가 허용하는 주체), post_via_waypoint=(지금 client 의 POST 상태 코드), direct_pod_ip=(지금 client 가 파드 IP 로 직접 부르면 allowed 또는 rejected) — 을 적고 그 아래 배운 것을 네 줄 이상 적으세요.

앞 단계 기록과 지금의 상태를 함께 보세요. 설명 줄에는 'ztunnel 과 waypoint 가 각각 무엇을 보고 무엇을 강제하는가' 와 'waypoint 를 붙일 때 L4 정책을 왜 함께 고쳐야 하는가' 를 적어 두세요.