From fa659cbb85a086631def75586cb2e1abf906082e Mon Sep 17 00:00:00 2001 From: Leo Ryu Date: Thu, 18 Nov 2021 14:29:07 +0800 Subject: [PATCH] fix(platform): log failed for user impersonation (#1662) --- api/platform/types.go | 23 ++++++++++ api/platform/v1/types.go | 23 ++++++++++ pkg/logagent/util/cluster.go | 50 +++------------------- pkg/platform/proxy/core/pod/storage/log.go | 10 ++--- pkg/platform/types/types.go | 1 + pkg/platform/util/client.go | 48 ++------------------- pkg/platform/util/rest/stream.go | 13 ++---- 7 files changed, 65 insertions(+), 103 deletions(-) diff --git a/api/platform/types.go b/api/platform/types.go index 6c54a4d20..09b3858ee 100644 --- a/api/platform/types.go +++ b/api/platform/types.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/client-go/rest" applicationv1 "tkestack.io/tke/api/application/v1" ) @@ -376,6 +377,28 @@ func (i ImpersonateUserExtra) ExtraToHeaders() map[string][]string { return res } +func (cc ClusterCredential) RESTConfig() *rest.Config { + config := &rest.Config{} + if cc.CACert != nil { + config.TLSClientConfig.CAData = cc.CACert + } else { + config.TLSClientConfig.Insecure = true + } + if cc.ClientCert != nil && cc.ClientKey != nil { + config.TLSClientConfig.CertData = cc.ClientCert + config.TLSClientConfig.KeyData = cc.ClientKey + } + if cc.Token != nil { + config.BearerToken = *cc.Token + } + + config.Impersonate.UserName = cc.Impersonate + config.Impersonate.Groups = cc.ImpersonateGroups + config.Impersonate.Extra = cc.ImpersonateUserExtra.ExtraToHeaders() + + return config +} + // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/api/platform/v1/types.go b/api/platform/v1/types.go index abe42f05f..1fe23f211 100644 --- a/api/platform/v1/types.go +++ b/api/platform/v1/types.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/client-go/rest" applicationv1 "tkestack.io/tke/api/application/v1" ) @@ -382,6 +383,28 @@ func (i ImpersonateUserExtra) ExtraToHeaders() map[string][]string { return res } +func (cc ClusterCredential) RESTConfig() *rest.Config { + config := &rest.Config{} + if cc.CACert != nil { + config.TLSClientConfig.CAData = cc.CACert + } else { + config.TLSClientConfig.Insecure = true + } + if cc.ClientCert != nil && cc.ClientKey != nil { + config.TLSClientConfig.CertData = cc.ClientCert + config.TLSClientConfig.KeyData = cc.ClientKey + } + if cc.Token != nil { + config.BearerToken = *cc.Token + } + + config.Impersonate.UserName = cc.Impersonate + config.Impersonate.Groups = cc.ImpersonateGroups + config.Impersonate.Extra = cc.ImpersonateUserExtra.ExtraToHeaders() + + return config +} + // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/logagent/util/cluster.go b/pkg/logagent/util/cluster.go index d8f8ea975..705c853e8 100644 --- a/pkg/logagent/util/cluster.go +++ b/pkg/logagent/util/cluster.go @@ -20,19 +20,16 @@ package util import ( "context" - "crypto/tls" - "crypto/x509" "fmt" - "net" "net/http" "net/url" "sync" - "time" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/client-go/kubernetes" + restclient "k8s.io/client-go/rest" platformversionedclient "tkestack.io/tke/api/client/clientset/versioned/typed/platform/v1" platformv1 "tkestack.io/tke/api/platform/v1" @@ -127,49 +124,12 @@ func GetClusterPodIP(ctx context.Context, clusterName, namespace, podName string // BuildTransport create the http transport for communicate to backend // kubernetes api server. func BuildTransportV1(credential *platformv1.ClusterCredential) (http.RoundTripper, error) { - transport := &http.Transport{ - Proxy: http.ProxyFromEnvironment, - DialContext: (&net.Dialer{ - Timeout: 5 * time.Second, - KeepAlive: 30 * time.Second, - }).DialContext, - MaxIdleConns: 100, - IdleConnTimeout: 90 * time.Second, - TLSHandshakeTimeout: 10 * time.Second, - } - if len(credential.CACert) > 0 { - transport.TLSClientConfig = &tls.Config{ - RootCAs: rootCertPool(credential.CACert), - } - } else { - transport.TLSClientConfig = &tls.Config{ - InsecureSkipVerify: true, - } - } + config := credential.RESTConfig() - if credential.ClientKey != nil && credential.ClientCert != nil { - cert, err := tls.X509KeyPair(credential.ClientCert, credential.ClientKey) - if err != nil { - return nil, err - } - transport.TLSClientConfig.Certificates = []tls.Certificate{cert} + transport, err := restclient.TransportFor(config) + if err != nil { + return nil, err } return transport, nil } - -// rootCertPool returns nil if caData is empty. When passed along, this will mean "use system CAs". -// When caData is not empty, it will be the ONLY information used in the CertPool. -func rootCertPool(caData []byte) *x509.CertPool { - // What we really want is a copy of x509.systemRootsPool, but that isn't exposed. It's difficult to build (see the go - // code for a look at the platform specific insanity), so we'll use the fact that RootCAs == nil gives us the system values - // It doesn't allow trusting either/or, but hopefully that won't be an issue - if len(caData) == 0 { - return nil - } - - // if we have caData, use it - certPool := x509.NewCertPool() - certPool.AppendCertsFromPEM(caData) - return certPool -} diff --git a/pkg/platform/proxy/core/pod/storage/log.go b/pkg/platform/proxy/core/pod/storage/log.go index 1b1f81796..2e73e7026 100644 --- a/pkg/platform/proxy/core/pod/storage/log.go +++ b/pkg/platform/proxy/core/pod/storage/log.go @@ -21,6 +21,10 @@ package storage import ( "context" "fmt" + "net/url" + "strconv" + "time" + corev1api "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation" @@ -28,9 +32,6 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" genericrest "k8s.io/apiserver/pkg/registry/generic/rest" "k8s.io/apiserver/pkg/registry/rest" - "net/url" - "strconv" - "time" platforminternalclient "tkestack.io/tke/api/client/clientset/internalversion/typed/platform/internalversion" "tkestack.io/tke/pkg/platform/util" restutil "tkestack.io/tke/pkg/platform/util/rest" @@ -87,7 +88,7 @@ func (r *LogREST) Get(ctx context.Context, name string, opts runtime.Object) (ru return nil, errors.NewInvalid(corev1api.SchemeGroupVersion.WithKind("PodLogOptions").GroupKind(), name, errs) } - location, transport, token, err := util.APIServerLocation(ctx, r.platformClient) + location, transport, _, err := util.APIServerLocation(ctx, r.platformClient) if err != nil { return nil, err } @@ -121,7 +122,6 @@ func (r *LogREST) Get(ctx context.Context, name string, opts runtime.Object) (ru location.RawQuery = params.Encode() return &restutil.LocationStreamer{ - Token: token, Location: location, Transport: transport, ContentType: "text/plain", diff --git a/pkg/platform/types/types.go b/pkg/platform/types/types.go index 3466a0944..d82008d96 100644 --- a/pkg/platform/types/types.go +++ b/pkg/platform/types/types.go @@ -96,6 +96,7 @@ func (c *Cluster) setRESTConfigDefaults(config *rest.Config) error { func (c *Cluster) RESTConfig(config *rest.Config) (*rest.Config, error) { err := c.setRESTConfigDefaults(config) + c.ClusterCredential.RESTConfig() if err != nil { return nil, err } diff --git a/pkg/platform/util/client.go b/pkg/platform/util/client.go index 112b40431..d0bc69dc1 100644 --- a/pkg/platform/util/client.go +++ b/pkg/platform/util/client.go @@ -20,8 +20,6 @@ package util import ( "context" - "crypto/tls" - "crypto/x509" "fmt" "math/rand" "net" @@ -29,7 +27,6 @@ import ( "path" "reflect" "strings" - "time" monitoringclient "github.com/coreos/prometheus-operator/pkg/client/versioned" mapset "github.com/deckarep/golang-set" @@ -123,32 +120,11 @@ func ResourceFromKind(kind string) string { // BuildTransport create the http transport for communicate to backend // kubernetes api server. func BuildTransport(credential *platform.ClusterCredential) (http.RoundTripper, error) { - transport := &http.Transport{ - Proxy: http.ProxyFromEnvironment, - DialContext: (&net.Dialer{ - Timeout: 5 * time.Second, - KeepAlive: 30 * time.Second, - }).DialContext, - MaxIdleConns: 100, - IdleConnTimeout: 90 * time.Second, - TLSHandshakeTimeout: 10 * time.Second, - } - if len(credential.CACert) > 0 { - transport.TLSClientConfig = &tls.Config{ - RootCAs: rootCertPool(credential.CACert), - } - } else { - transport.TLSClientConfig = &tls.Config{ - InsecureSkipVerify: true, - } - } + config := credential.RESTConfig() - if credential.ClientKey != nil && credential.ClientCert != nil { - cert, err := tls.X509KeyPair(credential.ClientCert, credential.ClientKey) - if err != nil { - return nil, err - } - transport.TLSClientConfig.Certificates = []tls.Certificate{cert} + transport, err := restclient.TransportFor(config) + if err != nil { + return nil, err } return transport, nil @@ -519,22 +495,6 @@ func ClusterV1Host(c *platformv1.Cluster) (string, error) { return ClusterHost(&cluster) } -// rootCertPool returns nil if caData is empty. When passed along, this will mean "use system CAs". -// When caData is not empty, it will be the ONLY information used in the CertPool. -func rootCertPool(caData []byte) *x509.CertPool { - // What we really want is a copy of x509.systemRootsPool, but that isn't exposed. It's difficult to build (see the go - // code for a look at the platform specific insanity), so we'll use the fact that RootCAs == nil gives us the system values - // It doesn't allow trusting either/or, but hopefully that won't be an issue - if len(caData) == 0 { - return nil - } - - // if we have caData, use it - certPool := x509.NewCertPool() - certPool.AppendCertsFromPEM(caData) - return certPool -} - func PrepareClusterScale(cluster *platform.Cluster, oldCluster *platform.Cluster) ([]platform.ClusterMachine, error) { allMachines, scalingMachines := []platform.ClusterMachine{}, []platform.ClusterMachine{} diff --git a/pkg/platform/util/rest/stream.go b/pkg/platform/util/rest/stream.go index a0d5b5ac4..77394ca68 100644 --- a/pkg/platform/util/rest/stream.go +++ b/pkg/platform/util/rest/stream.go @@ -23,21 +23,20 @@ package rest import ( "context" - "fmt" "io" + "net/http" + "net/url" + "strings" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" genericrest "k8s.io/apiserver/pkg/registry/generic/rest" "k8s.io/apiserver/pkg/registry/rest" - "net/http" - "net/url" - "strings" ) // LocationStreamer is a resource that streams the contents of a particular // location URL. type LocationStreamer struct { - Token string Location *url.URL Transport http.RoundTripper ContentType string @@ -84,10 +83,6 @@ func (s *LocationStreamer) InputStream(ctx context.Context, apiVersion, acceptHe // will be release properly. req = req.WithContext(ctx) - if s.Token != "" { - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", strings.TrimSpace(s.Token))) - } - resp, err := client.Do(req) if err != nil { return nil, false, "", err