mirror of
https://github.com/alibaba/higress.git
synced 2026-06-26 02:35:02 +08:00
feat: Enhance SSL passthrough support (#3943)
Signed-off-by: zijiren233 <pyh1670605849@gmail.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user