@@ -3,6 +3,7 @@ package proxy
33import (
44 "context"
55 "crypto/tls"
6+ "crypto/x509"
67 "errors"
78 "fmt"
89 "net/http"
@@ -25,9 +26,16 @@ import (
2526 clusterapis "github.com/karmada-io/karmada/pkg/apis/cluster"
2627)
2728
29+ type SecretGetterFunc func (context.Context , string , string ) (* corev1.Secret , error )
30+
2831// ConnectCluster returns a handler for proxy cluster.
29- func ConnectCluster (ctx context.Context , cluster * clusterapis.Cluster , proxyPath string , secretGetter func (context.Context , string , string ) (* corev1.Secret , error ), responder registryrest.Responder ) (http.Handler , error ) {
30- location , proxyTransport , err := Location (cluster )
32+ func ConnectCluster (ctx context.Context , cluster * clusterapis.Cluster , proxyPath string , secretGetter SecretGetterFunc , responder registryrest.Responder ) (http.Handler , error ) {
33+ tlsConfig , err := GetTlsConfigForCluster (ctx , cluster , secretGetter )
34+ if err != nil {
35+ return nil , err
36+ }
37+
38+ location , proxyTransport , err := Location (cluster , tlsConfig )
3139 if err != nil {
3240 return nil , err
3341 }
@@ -37,20 +45,20 @@ func ConnectCluster(ctx context.Context, cluster *clusterapis.Cluster, proxyPath
3745 return nil , fmt .Errorf ("the impersonatorSecretRef of cluster %s is nil" , cluster .Name )
3846 }
3947
40- secret , err := secretGetter (ctx , cluster .Spec .ImpersonatorSecretRef .Namespace , cluster .Spec .ImpersonatorSecretRef .Name )
48+ impersonateTokenSecret , err := secretGetter (ctx , cluster .Spec .ImpersonatorSecretRef .Namespace , cluster .Spec .ImpersonatorSecretRef .Name )
4149 if err != nil {
4250 return nil , err
4351 }
44-
45- impersonateToken , err := getImpersonateToken (cluster .Name , secret )
52+ impersonateToken , err := getImpersonateToken (cluster .Name , impersonateTokenSecret )
4653 if err != nil {
4754 return nil , fmt .Errorf ("failed to get impresonateToken for cluster %s: %v" , cluster .Name , err )
4855 }
4956
50- return newProxyHandler (location , proxyTransport , cluster , impersonateToken , responder )
57+ return newProxyHandler (location , proxyTransport , cluster , impersonateToken , responder , tlsConfig )
5158}
5259
53- func newProxyHandler (location * url.URL , proxyTransport http.RoundTripper , cluster * clusterapis.Cluster , impersonateToken string , responder registryrest.Responder ) (http.Handler , error ) {
60+ func newProxyHandler (location * url.URL , proxyTransport http.RoundTripper , cluster * clusterapis.Cluster , impersonateToken string ,
61+ responder registryrest.Responder , tlsConfig * tls.Config ) (http.Handler , error ) {
5462 return http .HandlerFunc (func (rw http.ResponseWriter , req * http.Request ) {
5563 requester , exist := request .UserFrom (req .Context ())
5664 if ! exist {
@@ -76,7 +84,7 @@ func newProxyHandler(location *url.URL, proxyTransport http.RoundTripper, cluste
7684 location .RawQuery = req .URL .RawQuery
7785
7886 upgradeDialer := NewUpgradeDialerWithConfig (UpgradeDialerWithConfig {
79- TLS : & tls. Config { InsecureSkipVerify : true }, //nolint:gosec
87+ TLS : tlsConfig ,
8088 Proxier : http .ProxyURL (proxyURL ),
8189 PingPeriod : time .Second * 5 ,
8290 Header : ParseProxyHeaders (cluster .Spec .ProxyHeader ),
@@ -94,14 +102,46 @@ func NewThrottledUpgradeAwareProxyHandler(location *url.URL, transport http.Roun
94102 return proxy .NewUpgradeAwareHandler (location , transport , wrapTransport , upgradeRequired , proxy .NewErrorResponder (responder ))
95103}
96104
105+ func GetTlsConfigForCluster (ctx context.Context , cluster * clusterapis.Cluster , secretGetter SecretGetterFunc ) (* tls.Config , error ) {
106+ // The secret is optional for a pull-mode cluster, if no secret just returns a config with root CA unset.
107+ if cluster .Spec .SecretRef == nil {
108+ return & tls.Config {
109+ MinVersion : tls .VersionTLS13 ,
110+ // Ignore false positive warning: "TLS InsecureSkipVerify may be true. (gosec)"
111+ // Whether to skip server certificate verification depends on the
112+ // configuration(.spec.insecureSkipTLSVerification, defaults to false) in a Cluster object.
113+ InsecureSkipVerify : cluster .Spec .InsecureSkipTLSVerification , //nolint:gosec
114+ }, nil
115+ }
116+ caSecret , err := secretGetter (ctx , cluster .Spec .SecretRef .Namespace , cluster .Spec .SecretRef .Name )
117+ if err != nil {
118+ return nil , err
119+ }
120+ caBundle , err := getClusterCABundle (cluster .Name , caSecret )
121+ if err != nil {
122+ return nil , fmt .Errorf ("failed to get CA bundle for cluster %s: %v" , cluster .Name , err )
123+ }
124+
125+ caCertPool := x509 .NewCertPool ()
126+ caCertPool .AppendCertsFromPEM ([]byte (caBundle ))
127+ return & tls.Config {
128+ RootCAs : caCertPool ,
129+ MinVersion : tls .VersionTLS13 ,
130+ // Ignore false positive warning: "TLS InsecureSkipVerify may be true. (gosec)"
131+ // Whether to skip server certificate verification depends on the
132+ // configuration(.spec.insecureSkipTLSVerification, defaults to false) in a Cluster object.
133+ InsecureSkipVerify : cluster .Spec .InsecureSkipTLSVerification , //nolint:gosec
134+ }, nil
135+ }
136+
97137// Location returns a URL to which one can send traffic for the specified cluster.
98- func Location (cluster * clusterapis.Cluster ) (* url.URL , http.RoundTripper , error ) {
138+ func Location (cluster * clusterapis.Cluster , tlsConfig * tls. Config ) (* url.URL , http.RoundTripper , error ) {
99139 location , err := constructLocation (cluster )
100140 if err != nil {
101141 return nil , nil , err
102142 }
103143
104- proxyTransport , err := createProxyTransport (cluster )
144+ proxyTransport , err := createProxyTransport (cluster , tlsConfig )
105145 if err != nil {
106146 return nil , nil , err
107147 }
@@ -122,12 +162,11 @@ func constructLocation(cluster *clusterapis.Cluster) (*url.URL, error) {
122162 return uri , nil
123163}
124164
125- func createProxyTransport (cluster * clusterapis.Cluster ) (* http.Transport , error ) {
165+ func createProxyTransport (cluster * clusterapis.Cluster , tlsConfig * tls. Config ) (* http.Transport , error ) {
126166 var proxyDialerFn utilnet.DialFunc
127- proxyTLSClientConfig := & tls.Config {InsecureSkipVerify : true } // #nosec
128167 trans := utilnet .SetTransportDefaults (& http.Transport {
129168 DialContext : proxyDialerFn ,
130- TLSClientConfig : proxyTLSClientConfig ,
169+ TLSClientConfig : tlsConfig ,
131170 })
132171
133172 if proxyURL := cluster .Spec .ProxyURL ; proxyURL != "" {
@@ -162,6 +201,14 @@ func getImpersonateToken(clusterName string, secret *corev1.Secret) (string, err
162201 return string (token ), nil
163202}
164203
204+ func getClusterCABundle (clusterName string , secret * corev1.Secret ) (string , error ) {
205+ caBundle , found := secret .Data [clusterapis .SecretCADataKey ]
206+ if ! found {
207+ return "" , fmt .Errorf ("the CA bundle of cluster %s is empty" , clusterName )
208+ }
209+ return string (caBundle ), nil
210+ }
211+
165212func skipGroup (group string ) bool {
166213 switch group {
167214 case user .AllAuthenticated , user .AllUnauthenticated :
0 commit comments