#!/usr/bin/env bash # T11 (run 2 / re-run): identity-based AuthorizationPolicy DENY - L7 (HTTP, expect 403) vs L4 (raw TCP, expect # connection reset). Re-runnable reproduction script. # # CORRECTION applied vs run 1: run 1 curled services using the real kubeadm clusterDomain FQDN # (*.svc.homelab.local). istiod runs with the default --domain=cluster.local, so Pilot generates each # service's HTTP VirtualHost "domains" list using the *.svc.cluster.local suffix (and short names), # regardless of clusterDomain/CoreDNS. A Host header of *.svc.homelab.local matches NONE of those domains # and falls through to the mesh-wide passthrough route, bypassing mTLS origination and AuthorizationPolicy # (RBAC) entirely for HTTP - that's why run 1 saw l7_deny=200 instead of the expected 403. # # Corrected adaptation rule (see harness-notes.md CORRECTION section): # - curl k8s services by SHORT name (matches the VirtualHost domains list Pilot actually generates). # - AuthorizationPolicy principals stay cluster.local/... (SPIFFE trustDomain, unrelated to clusterDomain). set -euo pipefail NS="istio-vt-t11-r2" DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cleanup() { echo "--- cleanup: deleting namespace ${NS} ---" kubectl delete namespace "${NS}" --wait=false --ignore-not-found } trap cleanup EXIT echo "--- create namespace ${NS} (istio-injection=enabled) ---" kubectl create namespace "${NS}" kubectl label namespace "${NS}" istio-injection=enabled echo "--- apply manifest.yaml (client, echo deploy+svc, tcp-target pod+svc, 2x AuthorizationPolicy DENY) ---" kubectl apply -f "${DIR}/manifest.yaml" echo "--- wait for client Ready ---" kubectl -n "${NS}" wait --for=condition=Ready pod/client --timeout=90s echo "--- wait for tcp-target Ready ---" kubectl -n "${NS}" wait --for=condition=Ready pod/tcp-target --timeout=60s echo "--- wait for echo Deployment rollout ---" kubectl -n "${NS}" rollout status deploy/echo --timeout=90s echo "--- settle: allow AuthorizationPolicy + endpoint metadata to propagate ---" sleep 5 echo "--- L7 (HTTP) request to echo, using SHORT name (corrected): expect 403 per pass_criteria ---" kubectl -n "${NS}" exec client -c curl -- curl -s -o /dev/null -w 'l7_deny=%{http_code}\n' \ "http://echo.${NS}/" echo "--- echo istio-proxy access log tail ---" ECHO_POD=$(kubectl -n "${NS}" get pod -l app=echo -o jsonpath='{.items[0].metadata.name}') kubectl -n "${NS}" logs "${ECHO_POD}" -c istio-proxy --since=20s | tail -3 echo "--- L4 (raw TCP) request to tcp-target, using SHORT name: expect no HTTP code / connection reset ---" set +e kubectl -n "${NS}" exec client -c curl -- curl -s -o /dev/null -w 'l4_deny_code=%{http_code}\n' \ --max-time 4 "http://tcp-target.${NS}:9090/" echo "l4_deny_exit=$?" set -e echo "--- tcp-target istio-proxy access log tail ---" kubectl -n "${NS}" logs tcp-target -c istio-proxy --since=20s | tail -3