feat: Enhance SSL passthrough support (#3943)

Signed-off-by: zijiren233 <pyh1670605849@gmail.com>
This commit is contained in:
zijiren
2026-06-22 21:06:42 +08:00
committed by GitHub
parent f060c9f51d
commit 9c13b6418c
14 changed files with 3178 additions and 46 deletions

View File

@@ -15,6 +15,7 @@
package common
import (
"strconv"
"strings"
"time"
@@ -23,6 +24,7 @@ import (
"istio.io/istio/pkg/cluster"
"istio.io/istio/pkg/config"
gatewaytool "istio.io/istio/pkg/config/gateway"
"istio.io/istio/pkg/config/protocol"
listerv1 "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/cache"
@@ -78,6 +80,20 @@ func (w *WrapperGateway) IsHTTPS() bool {
return false
}
func CreateSSLPassthroughServer(host string, port uint32, clusterId cluster.ID) *networking.Server {
return &networking.Server{
Port: &networking.Port{
Number: port,
Protocol: string(protocol.TLS),
Name: CreateConvertedName("tls-"+strconv.FormatUint(uint64(port), 10)+"-ingress", clusterId.String()),
},
Hosts: []string{WildcardHost(host)},
Tls: &networking.ServerTLSSettings{
Mode: networking.ServerTLSSettings_PASSTHROUGH,
},
}
}
type WrapperHTTPRoute struct {
HTTPRoute *networking.HTTPRoute
WrapperConfig *WrapperConfig
@@ -111,6 +127,50 @@ type WrapperVirtualService struct {
AppRoot string
}
func (w *WrapperVirtualService) HasTLSRouteForHost(host string) bool {
if w == nil || w.VirtualService == nil {
return false
}
host = WildcardHost(host)
for _, route := range w.VirtualService.Tls {
for _, match := range route.Match {
for _, sniHost := range match.SniHosts {
if WildcardHost(sniHost) == host {
return true
}
}
}
}
return false
}
func NewWrapperVirtualService(host string, wrapper *WrapperConfig) *WrapperVirtualService {
return &WrapperVirtualService{
VirtualService: &networking.VirtualService{
Hosts: []string{WildcardHost(host)},
},
WrapperConfig: wrapper,
}
}
func CreateTLSRoute(host string, routeDestination []*networking.RouteDestination) *networking.TLSRoute {
return &networking.TLSRoute{
Match: []*networking.TLSMatchAttributes{
{
SniHosts: []string{WildcardHost(host)},
},
},
Route: routeDestination,
}
}
func WildcardHost(host string) string {
if host == "" {
return "*"
}
return host
}
type WrapperTrafficPolicy struct {
TrafficPolicy *networking.TrafficPolicy
PortTrafficPolicy *networking.TrafficPolicy_PortTrafficPolicy

View File

@@ -145,6 +145,41 @@ func (i *IngressDomainCache) Extract() model.IngressDomainCollection {
}
}
func SameConfig(left *config.Config, right *config.Config) bool {
if left == nil || right == nil {
return left == right
}
return GetClusterId(left.Annotations) == GetClusterId(right.Annotations) &&
left.Namespace == right.Namespace &&
left.Name == right.Name
}
func IsPassthroughTLSHostOwner(convertOptions *ConvertOptions, cfg *config.Config, host string) bool {
if convertOptions == nil || convertOptions.PassthroughTLSHostOwners == nil {
return true
}
return SameConfig(convertOptions.PassthroughTLSHostOwners[host], cfg)
}
func PassthroughTLSHostOwner(convertOptions *ConvertOptions, host string) *config.Config {
if convertOptions == nil || len(convertOptions.PassthroughTLSHostOwners) == 0 {
return nil
}
return convertOptions.PassthroughTLSHostOwners[host]
}
func HasPassthroughTLSHostOwner(convertOptions *ConvertOptions, cfg *config.Config) bool {
if convertOptions == nil || len(convertOptions.PassthroughTLSHostOwners) == 0 {
return false
}
for _, owner := range convertOptions.PassthroughTLSHostOwners {
if SameConfig(owner, cfg) {
return true
}
}
return false
}
type ConvertOptions struct {
HostWithRule2Ingress map[string]*config.Config
@@ -167,6 +202,9 @@ type ConvertOptions struct {
CanaryIngresses []*WrapperConfig
// Host to the first root-path ingress owner for hosts that have TLS passthrough enabled.
PassthroughTLSHostOwners map[string]*config.Config
Service2TrafficPolicy map[ServiceKey]*WrapperTrafficPolicy
ServiceWrappers map[string]*ServiceWrapper

View File

@@ -18,10 +18,48 @@ import (
"testing"
"github.com/stretchr/testify/assert"
networking "istio.io/api/networking/v1alpha3"
"istio.io/istio/pilot/pkg/model"
"istio.io/istio/pkg/config"
)
func TestWildcardHostForSSLPassthrough(t *testing.T) {
server := CreateSSLPassthroughServer("", 443, "")
assert.Equal(t, []string{"*"}, server.Hosts)
vs := NewWrapperVirtualService("", &WrapperConfig{})
assert.Equal(t, []string{"*"}, vs.VirtualService.Hosts)
route := CreateTLSRoute("", []*networking.RouteDestination{{Weight: 100}})
assert.Equal(t, []string{"*"}, route.Match[0].SniHosts)
vs.VirtualService.Tls = append(vs.VirtualService.Tls, route)
assert.True(t, vs.HasTLSRouteForHost(""))
}
func TestPassthroughTLSHostOwnerNilMapAllowsStandaloneConversion(t *testing.T) {
cfg := &config.Config{
Meta: config.Meta{
Namespace: "default",
Name: "tls-passthrough",
},
}
// A nil owner map means the caller did not prepare ownership from the full ingress snapshot.
assert.True(t, IsPassthroughTLSHostOwner(&ConvertOptions{}, cfg, "example.com"))
assert.Nil(t, PassthroughTLSHostOwner(&ConvertOptions{}, "example.com"))
// A non-nil owner map means ownership has been prepared and missing hosts have no owner.
options := &ConvertOptions{
PassthroughTLSHostOwners: map[string]*config.Config{},
}
assert.False(t, IsPassthroughTLSHostOwner(options, cfg, "example.com"))
assert.Nil(t, PassthroughTLSHostOwner(options, "example.com"))
options.PassthroughTLSHostOwners["example.com"] = cfg
assert.True(t, IsPassthroughTLSHostOwner(options, cfg, "example.com"))
assert.Equal(t, cfg, PassthroughTLSHostOwner(options, "example.com"))
}
func TestIngressDomainCache(t *testing.T) {
cache := NewIngressDomainCache()
assert.NotNil(t, cache)