change cluster schema (#2026)
* change cluster schema * change cluster schema
This commit is contained in:
221
vendor/sigs.k8s.io/kubefed/pkg/controller/util/cluster_util.go
generated
vendored
Normal file
221
vendor/sigs.k8s.io/kubefed/pkg/controller/util/cluster_util.go
generated
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
pkgruntime "k8s.io/apimachinery/pkg/runtime"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/client-go/transport"
|
||||
"k8s.io/klog"
|
||||
|
||||
fedv1b1 "sigs.k8s.io/kubefed/pkg/apis/core/v1beta1"
|
||||
"sigs.k8s.io/kubefed/pkg/client/generic"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultKubeFedSystemNamespace = "kube-federation-system"
|
||||
|
||||
KubeAPIQPS = 20.0
|
||||
KubeAPIBurst = 30
|
||||
TokenKey = "token"
|
||||
|
||||
KubeFedConfigName = "kubefed"
|
||||
)
|
||||
|
||||
// BuildClusterConfig returns a restclient.Config that can be used to configure
|
||||
// a client for the given KubeFedCluster or an error. The client is used to
|
||||
// access kubernetes secrets in the kubefed namespace.
|
||||
func BuildClusterConfig(fedCluster *fedv1b1.KubeFedCluster, client generic.Client, fedNamespace string) (*restclient.Config, error) {
|
||||
clusterName := fedCluster.Name
|
||||
|
||||
apiEndpoint := fedCluster.Spec.APIEndpoint
|
||||
// TODO(marun) Remove when validation ensures a non-empty value.
|
||||
if apiEndpoint == "" {
|
||||
return nil, errors.Errorf("The api endpoint of cluster %s is empty", clusterName)
|
||||
}
|
||||
|
||||
secretName := fedCluster.Spec.SecretRef.Name
|
||||
if secretName == "" {
|
||||
return nil, errors.Errorf("Cluster %s does not have a secret name", clusterName)
|
||||
}
|
||||
secret := &apiv1.Secret{}
|
||||
err := client.Get(context.TODO(), secret, fedNamespace, secretName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
token, tokenFound := secret.Data[TokenKey]
|
||||
if !tokenFound || len(token) == 0 {
|
||||
return nil, errors.Errorf("The secret for cluster %s is missing a non-empty value for %q", clusterName, TokenKey)
|
||||
}
|
||||
|
||||
clusterConfig, err := clientcmd.BuildConfigFromFlags(apiEndpoint, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clusterConfig.CAData = fedCluster.Spec.CABundle
|
||||
clusterConfig.BearerToken = string(token)
|
||||
clusterConfig.QPS = KubeAPIQPS
|
||||
clusterConfig.Burst = KubeAPIBurst
|
||||
|
||||
if len(fedCluster.Spec.DisabledTLSValidations) != 0 {
|
||||
klog.V(1).Infof("Cluster %s will use a custom transport for TLS certificate validation", fedCluster.Name)
|
||||
if err = CustomizeTLSTransport(fedCluster, clusterConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return clusterConfig, nil
|
||||
}
|
||||
|
||||
// IsPrimaryCluster checks if the caller is working with objects for the
|
||||
// primary cluster by checking if the UIDs match for both ObjectMetas passed
|
||||
// in.
|
||||
// TODO (font): Need to revisit this when cluster ID is available.
|
||||
func IsPrimaryCluster(obj, clusterObj pkgruntime.Object) bool {
|
||||
meta := MetaAccessor(obj)
|
||||
clusterMeta := MetaAccessor(clusterObj)
|
||||
return meta.GetUID() == clusterMeta.GetUID()
|
||||
}
|
||||
|
||||
// CustomizeTLSTransport replaces the restclient.Config.Transport with one that
|
||||
// implements the desired TLS certificate validations
|
||||
func CustomizeTLSTransport(fedCluster *fedv1b1.KubeFedCluster, clientConfig *restclient.Config) error {
|
||||
clientTransportConfig, err := clientConfig.TransportConfig()
|
||||
if err != nil {
|
||||
return errors.Errorf("Cluster %s client transport config error: %s", fedCluster.Name, err)
|
||||
}
|
||||
transportConfig, err := transport.TLSConfigFor(clientTransportConfig)
|
||||
if err != nil {
|
||||
return errors.Errorf("Cluster %s transport error: %s", fedCluster.Name, err)
|
||||
}
|
||||
|
||||
err = CustomizeCertificateValidation(fedCluster, transportConfig)
|
||||
if err != nil {
|
||||
return errors.Errorf("Cluster %s custom certificate validation error: %s", fedCluster.Name, err)
|
||||
}
|
||||
|
||||
// using the same defaults as http.DefaultTransport
|
||||
clientConfig.Transport = &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
DualStack: true,
|
||||
}).DialContext,
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
TLSClientConfig: transportConfig,
|
||||
}
|
||||
clientConfig.TLSClientConfig = restclient.TLSClientConfig{}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CustomizeCertificateValidation modifies an existing tls.Config to disable the
|
||||
// desired TLS checks in KubeFedCluster config
|
||||
func CustomizeCertificateValidation(fedCluster *fedv1b1.KubeFedCluster, tlsConfig *tls.Config) error {
|
||||
// InsecureSkipVerify must be enabled to prevent early validation errors from
|
||||
// returning before VerifyPeerCertificate is run
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
|
||||
var ignoreSubjectName, ignoreValidityPeriod bool
|
||||
for _, validation := range fedCluster.Spec.DisabledTLSValidations {
|
||||
switch fedv1b1.TLSValidation(validation) {
|
||||
case fedv1b1.TLSAll:
|
||||
klog.V(1).Infof("Cluster %s will not perform TLS certificate validation", fedCluster.Name)
|
||||
return nil
|
||||
case fedv1b1.TLSSubjectName:
|
||||
ignoreSubjectName = true
|
||||
case fedv1b1.TLSValidityPeriod:
|
||||
ignoreValidityPeriod = true
|
||||
}
|
||||
}
|
||||
|
||||
// Normal TLS SubjectName validation uses the conn dnsname for validation,
|
||||
// but this is not available when using a VerifyPeerCertificate functions.
|
||||
// As a workaround, we will fill the tls.Config.ServerName with the URL host
|
||||
// specified as the KubeFedCluster API target
|
||||
if !ignoreSubjectName && tlsConfig.ServerName == "" {
|
||||
apiURL, err := url.Parse(fedCluster.Spec.APIEndpoint)
|
||||
if err != nil {
|
||||
return errors.Errorf("failed to identify a valid host from APIEndpoint for use in SubjectName validation")
|
||||
}
|
||||
tlsConfig.ServerName = apiURL.Hostname()
|
||||
}
|
||||
|
||||
// VerifyPeerCertificate uses the same logic as crypto/tls Conn.verifyServerCertificate
|
||||
// but uses a modified set of options to ignore specific validations
|
||||
tlsConfig.VerifyPeerCertificate = func(certificates [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
opts := x509.VerifyOptions{
|
||||
Roots: tlsConfig.RootCAs,
|
||||
CurrentTime: time.Now(),
|
||||
Intermediates: x509.NewCertPool(),
|
||||
DNSName: tlsConfig.ServerName,
|
||||
}
|
||||
if tlsConfig.Time != nil {
|
||||
opts.CurrentTime = tlsConfig.Time()
|
||||
}
|
||||
|
||||
certs := make([]*x509.Certificate, len(certificates))
|
||||
for i, asn1Data := range certificates {
|
||||
cert, err := x509.ParseCertificate(asn1Data)
|
||||
if err != nil {
|
||||
return errors.New("tls: failed to parse certificate from server: " + err.Error())
|
||||
}
|
||||
certs[i] = cert
|
||||
}
|
||||
|
||||
for i, cert := range certs {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
opts.Intermediates.AddCert(cert)
|
||||
}
|
||||
|
||||
if ignoreSubjectName {
|
||||
// set the DNSName to nil to ignore the name validation
|
||||
opts.DNSName = ""
|
||||
klog.V(1).Infof("Cluster %s will not perform tls certificate SubjectName validation", fedCluster.Name)
|
||||
}
|
||||
if ignoreValidityPeriod {
|
||||
// set the CurrentTime to immediately after the certificate start time
|
||||
// this will ensure that certificate passes the validity period check
|
||||
opts.CurrentTime = certs[0].NotBefore.Add(time.Second)
|
||||
klog.V(1).Infof("Cluster %s will not perform tls certificate ValidityPeriod validation", fedCluster.Name)
|
||||
}
|
||||
|
||||
_, err := certs[0].Verify(opts)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user