#!/usr/bin/env bash # T20: upstream_transport_failure_reason field -- mTLS mode mismatch vs pure TCP connect failure. # Re-runnable script. Creates istio-vt-t20 namespace, exercises both cases, cleans up on exit. set -euo pipefail NS=istio-vt-t20 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 "[setup] creating namespace ${NS} with istio-injection=enabled" kubectl create namespace "${NS}" kubectl label namespace "${NS}" istio-injection=enabled --overwrite echo "[apply] client pod + echo deployment/service (no mTLS policy yet)" kubectl apply -f "${DIR}/client-echo.yaml" kubectl -n "${NS}" wait --for=condition=Ready pod/client --timeout=90s kubectl -n "${NS}" rollout status deploy/echo --timeout=90s echo echo "=== case A: pure TCP connect failure (closed port, no mTLS involved) ===" set +e kubectl -n "${NS}" exec client -c curl -- curl -s -o /dev/null --max-time 2 \ "http://echo.${NS}.svc.homelab.local:59999/" echo "curl exit code: $?" set -e # Envoy's PassthroughCluster TCP idle-timeout is ~10s, so the access log line is only # flushed some seconds after the client gave up locally. sleep 12 echo "--- istio-proxy access log (case A) ---" kubectl -n "${NS}" logs client -c istio-proxy --tail=5 echo echo "=== case B: mTLS mode mismatch (server STRICT, client DestinationRule forced to DISABLE) ===" echo "NOTE: the cluster's actual DNS domain is homelab.local, but Istio's CDS/RDS registry" echo "hostnames are hardcoded to the cluster.local suffix regardless -- a DestinationRule" echo "targeting *.svc.homelab.local will NOT attach to the real outbound cluster. This script" echo "applies the DestinationRule/PeerAuthentication with the homelab.local host (as literally" echo "specified) AND a corrected variant with the cluster.local host (to control for the DNS" echo "domain confound and confirm the DR actually attaches to outbound|80||echo...)." kubectl apply -f "${DIR}/echo-strict.yaml" -f "${DIR}/echo-mtls-mismatch-dr.yaml" sleep 8 set +e kubectl -n "${NS}" exec client -c curl -- curl -s -o /dev/null --max-time 3 \ "http://echo.${NS}.svc.homelab.local/" echo "curl exit code: $?" set -e sleep 3 echo "--- istio-proxy access log (case B, as literally specified) ---" kubectl -n "${NS}" logs client -c istio-proxy --tail=5 echo echo "--- control: corrected DestinationRule targeting the real registered hostname ---" kubectl apply -f "${DIR}/echo-mtls-mismatch-dr-corrected.yaml" sleep 5 CLUSTERIP=$(kubectl -n "${NS}" get svc echo -o jsonpath='{.spec.clusterIP}') set +e kubectl -n "${NS}" exec client -c curl -- curl -s -o /dev/null --max-time 3 \ --resolve "echo.${NS}.svc.cluster.local:80:${CLUSTERIP}" \ "http://echo.${NS}.svc.cluster.local/" echo "curl exit code: $?" set -e sleep 3 echo "--- istio-proxy access log (case B, control via properly-attached DR) ---" kubectl -n "${NS}" logs client -c istio-proxy --tail=3 echo echo "[done] see result.txt in this directory for the full annotated capture and analysis."