diff --git a/pkg/apis/cluster/v1alpha1/clustergateway_types.go b/pkg/apis/cluster/v1alpha1/clustergateway_types.go index e3357c75..1d5ef540 100644 --- a/pkg/apis/cluster/v1alpha1/clustergateway_types.go +++ b/pkg/apis/cluster/v1alpha1/clustergateway_types.go @@ -108,6 +108,8 @@ type ClusterEndpointConst struct { // Insecure indicates the cluster should be access'd w/o verifying // CA certificate at client-side. Insecure *bool `json:"insecure,omitempty"` + // ProxyURL indicates the proxy url of the server + ProxyURL *string `json:"proxy-url,omitempty"` } type ClusterAccessCredential struct { diff --git a/pkg/apis/cluster/v1alpha1/clustergateway_types_secret.go b/pkg/apis/cluster/v1alpha1/clustergateway_types_secret.go index 0e359794..7622306d 100644 --- a/pkg/apis/cluster/v1alpha1/clustergateway_types_secret.go +++ b/pkg/apis/cluster/v1alpha1/clustergateway_types_secret.go @@ -189,6 +189,10 @@ func convert(caData []byte, apiServerEndpoint string, insecure bool, secret *v1. if !ok { endpointType = string(ClusterEndpointTypeConst) } + var proxyURL *string + if url, useProxy := secret.Data["proxy-url"]; useProxy && len(url) > 0 { + proxyURL = pointer.String(string(url)) + } switch ClusterEndpointType(endpointType) { case ClusterEndpointTypeClusterProxy: c.Spec.Access.Endpoint = &ClusterEndpoint{ @@ -206,6 +210,7 @@ func convert(caData []byte, apiServerEndpoint string, insecure bool, secret *v1. Const: &ClusterEndpointConst{ Address: apiServerEndpoint, Insecure: &insecure, + ProxyURL: proxyURL, }, } } else { @@ -214,6 +219,7 @@ func convert(caData []byte, apiServerEndpoint string, insecure bool, secret *v1. Const: &ClusterEndpointConst{ Address: apiServerEndpoint, CABundle: caData, + ProxyURL: proxyURL, }, } } diff --git a/pkg/apis/cluster/v1alpha1/transport.go b/pkg/apis/cluster/v1alpha1/transport.go index 34a7b5a7..f15698fd 100644 --- a/pkg/apis/cluster/v1alpha1/transport.go +++ b/pkg/apis/cluster/v1alpha1/transport.go @@ -3,11 +3,11 @@ package v1alpha1 import ( "context" "net" + "net/http" "net/url" "strconv" "time" - "github.com/oam-dev/cluster-gateway/pkg/config" "github.com/pkg/errors" "google.golang.org/grpc" grpccredentials "google.golang.org/grpc/credentials" @@ -16,6 +16,8 @@ import ( restclient "k8s.io/client-go/rest" konnectivity "sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client" "sigs.k8s.io/apiserver-network-proxy/pkg/util" + + "github.com/oam-dev/cluster-gateway/pkg/config" ) var DialerGetter = func(ctx context.Context) (k8snet.DialFunc, error) { @@ -72,6 +74,14 @@ func NewConfigFromCluster(ctx context.Context, c *ClusterGateway) (*restclient.C host = u.Host } cfg.ServerName = host // apiserver may listen on SNI cert + + if c.Spec.Access.Endpoint.Const.ProxyURL != nil { + _url, _err := url.Parse(*c.Spec.Access.Endpoint.Const.ProxyURL) + if _err != nil { + return nil, _err + } + cfg.Proxy = http.ProxyURL(_url) + } case ClusterEndpointTypeClusterProxy: cfg.Host = c.Name // the same as the cluster name cfg.Insecure = true diff --git a/pkg/apis/cluster/v1alpha1/transport_test.go b/pkg/apis/cluster/v1alpha1/transport_test.go index 2a5a172b..bc517f2c 100644 --- a/pkg/apis/cluster/v1alpha1/transport_test.go +++ b/pkg/apis/cluster/v1alpha1/transport_test.go @@ -3,6 +3,8 @@ package v1alpha1 import ( "context" "net" + "net/http" + "net/url" "testing" "time" @@ -19,6 +21,8 @@ func TestClusterRestConfigConversion(t *testing.T) { testCAData := []byte(`test-ca`) testCertData := []byte(`test-cert`) testKeyData := []byte(`test-key`) + proxyURLData := []byte(`socks5://localhost:1080`) + proxyURL, _ := url.Parse(string(proxyURLData)) testDialFunc := func(ctx context.Context, net, addr string) (net.Conn, error) { return nil, nil } @@ -179,6 +183,38 @@ func TestClusterRestConfigConversion(t *testing.T) { }, }, }, + { + name: "proxy-url should work", + clusterGateway: &ClusterGateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-cluster", + }, + Spec: ClusterGatewaySpec{ + Access: ClusterAccess{ + Endpoint: &ClusterEndpoint{ + Type: ClusterEndpointTypeConst, + Const: &ClusterEndpointConst{ + Address: "https://foo.bar:33", + ProxyURL: pointer.String(string(proxyURLData)), + }, + }, + Credential: &ClusterAccessCredential{ + Type: CredentialTypeServiceAccountToken, + ServiceAccountToken: testToken, + }, + }, + }, + }, + expectedCfg: &rest.Config{ + Host: "https://foo.bar:33", + Timeout: 40 * time.Second, + BearerToken: testToken, + Proxy: http.ProxyURL(proxyURL), + TLSClientConfig: rest.TLSClientConfig{ + ServerName: "foo.bar", + }, + }, + }, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { @@ -194,6 +230,11 @@ func TestClusterRestConfigConversion(t *testing.T) { c.expectedCfg.Dial = nil cfg.Dial = nil } + if cfg.Proxy != nil { + assert.NotNil(t, c.expectedCfg.Proxy) + cfg.Proxy = nil + c.expectedCfg.Proxy = nil + } assert.Equal(t, c.expectedCfg, cfg) }) }