diff --git a/cmd/atenet/internal/router/egressmanifest_test.go b/cmd/atenet/internal/router/egressmanifest_test.go index 398de60df..5f0c00425 100644 --- a/cmd/atenet/internal/router/egressmanifest_test.go +++ b/cmd/atenet/internal/router/egressmanifest_test.go @@ -16,6 +16,7 @@ package router import ( "os" + "slices" "strings" "testing" "time" @@ -31,6 +32,49 @@ var egressManifests = []string{ "../../../../manifests/ate-install/atenet-egress-with-sdsmint.yaml", } +// Missing max_session_keys defaults to 1, so it must be explicitly zero. +// Each MITM origin cluster serves multiple SNIs through one TLS context. +func TestEgressOriginDisablesSessionResumption(t *testing.T) { + var bootstrap struct { + StaticResources struct { + Clusters []struct { + Name string `json:"name"` + TransportSocket struct { + TypedConfig struct { + Type string `json:"@type"` + MaxSessionKeys *uint32 `json:"max_session_keys"` + } `json:"typed_config"` + } `json:"transport_socket"` + } `json:"clusters"` + } `json:"static_resources"` + } + raw := envoyConfig(t, "../../../../manifests/ate-install/atenet-egress-with-sdsmint.yaml") + if err := yaml.Unmarshal([]byte(raw), &bootstrap); err != nil { + t.Fatal(err) + } + var checked []string + for _, cluster := range bootstrap.StaticResources.Clusters { + ctx := cluster.TransportSocket.TypedConfig + if ctx.Type != "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext" { + continue + } + checked = append(checked, cluster.Name) + t.Run(cluster.Name, func(t *testing.T) { + if ctx.MaxSessionKeys == nil { + t.Fatal("max_session_keys is missing; Envoy enables session resumption by default") + } + if *ctx.MaxSessionKeys != 0 { + t.Errorf("max_session_keys = %d, want 0 to prevent cross-SNI session reuse", *ctx.MaxSessionKeys) + } + }) + } + slices.Sort(checked) + want := []string{"egress_forward_proxy", "egress_forward_proxy_grpc", "egress_original_dst_tls", "egress_original_dst_tls_grpc"} + if !slices.Equal(checked, want) { + t.Errorf("checked TLS clusters = %v, want %v", checked, want) + } +} + // TestEgressManifestsDisableTheConnectTimeout is the static-config half of // TestBuildConnectRoutes_DisablesTimeout: Envoy applies a route's timeout to a // CONNECT tunnel's whole lifetime rather than to its headers, so a route left diff --git a/manifests/ate-install/atenet-egress-with-sdsmint.yaml b/manifests/ate-install/atenet-egress-with-sdsmint.yaml index 0f67d1be3..d5eb21008 100644 --- a/manifests/ate-install/atenet-egress-with-sdsmint.yaml +++ b/manifests/ate-install/atenet-egress-with-sdsmint.yaml @@ -779,6 +779,11 @@ data: # The only cluster that dials the internet. Reached from the MITM leg, so # the host it resolves comes from the decrypted request's own Host header # rather than from the CONNECT authority. + # Disable session resumption on all four origin TLS clusters: Envoy 1.39 + # shares sessions across SNIs within a client context, which can fail SAN + # validation if another origin accepts the ticket. Revisit after upgrading + # to a build with https://github.com/envoyproxy/envoy/pull/45982 enabled. + # New TLS connections use full handshakes; HTTP connection reuse is unchanged. - name: egress_forward_proxy lb_policy: CLUSTER_PROVIDED connect_timeout: 5s @@ -809,6 +814,7 @@ data: name: envoy.transport_sockets.tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext + max_session_keys: 0 common_tls_context: validation_context: trusted_ca: @@ -837,6 +843,7 @@ data: name: envoy.transport_sockets.tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext + max_session_keys: 0 common_tls_context: validation_context: trusted_ca: @@ -896,6 +903,7 @@ data: name: envoy.transport_sockets.tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext + max_session_keys: 0 common_tls_context: validation_context: trusted_ca: @@ -918,6 +926,7 @@ data: name: envoy.transport_sockets.tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext + max_session_keys: 0 common_tls_context: validation_context: trusted_ca: