sigs.k8s.io/cluster-api@v1.7.1/util/kubeconfig/kubeconfig_test.go (about)

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package kubeconfig
    18  
    19  import (
    20  	"crypto/rand"
    21  	"crypto/rsa"
    22  	"crypto/x509"
    23  	"crypto/x509/pkix"
    24  	"math/big"
    25  	"testing"
    26  	"time"
    27  
    28  	. "github.com/onsi/gomega"
    29  	corev1 "k8s.io/api/core/v1"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	"k8s.io/client-go/tools/clientcmd"
    32  	"k8s.io/client-go/tools/clientcmd/api"
    33  	ctrl "sigs.k8s.io/controller-runtime"
    34  	"sigs.k8s.io/controller-runtime/pkg/client"
    35  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    36  
    37  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    38  	"sigs.k8s.io/cluster-api/util"
    39  	"sigs.k8s.io/cluster-api/util/certs"
    40  	"sigs.k8s.io/cluster-api/util/secret"
    41  )
    42  
    43  var (
    44  	ctx = ctrl.SetupSignalHandler()
    45  
    46  	validKubeConfig = `
    47  clusters:
    48  - cluster:
    49      certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1ERXhNREU0TURBME1Gb1hEVEk1TURFd056RTRNREEwTUZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBT1EvCmVndmViNk1qMHkzM3hSbGFjczd6OXE4QTNDajcrdnRrZ0pUSjRUSVB4TldRTEd0Q0dmL0xadzlHMW9zNmRKUHgKZFhDNmkwaHA5czJuT0Y2VjQvREUrYUNTTU45VDYzckdWb2s0TkcwSlJPYmlRWEtNY1VQakpiYm9PTXF2R2lLaAoyMGlFY0h5K3B4WkZOb3FzdnlaRGM5L2dRSHJVR1FPNXp6TDNHZGhFL0k1Nkczek9JaWhhbFRHSTNaakRRS05CCmVFV3FONTVDcHZzT3I1b0ZnTmZZTXk2YzZ4WXlUTlhWSUkwNFN0Z2xBbUk4bzZWaTNUVEJhZ1BWaldIVnRha1EKU2w3VGZtVUlIdndKZUo3b2hxbXArVThvaGVTQUIraHZSbDIrVHE5NURTemtKcmRjNmphcyswd2FWaEJydEh1agpWMU15NlNvV2VVUlkrdW5VVFgwQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFIT2thSXNsd0pCOE5PaENUZkF4UWlnaUc1bEMKQlo0LytGeHZ3Y1pnWGhlL0IyUWo1UURMNWlRUU1VL2NqQ0tyYUxkTFFqM1o1aHA1dzY0K2NWRUg3Vm9PSTFCaQowMm13YTc4eWo4aDNzQ2lLQXJiU21kKzNld1QrdlNpWFMzWk9EYWRHVVRRa1BnUHB0THlaMlRGakF0SW43WjcyCmpnYlVnT2FXaklKbnlwRVJ5UmlSKzBvWlk4SUlmWWFsTHUwVXlXcmkwaVhNRmZqQUQ1UVNURy8zRGN5djhEN1UKZHBxU2l5ekJkZVRjSExyenpEbktBeXhQWWgvcWpKZ0tRdEdIakhjY0FCSE1URlFtRy9Ea1pNTnZWL2FZSnMrKwp0aVJCbHExSFhlQ0d4aExFcGdQcGxVb3IrWmVYTGF2WUo0Z2dMVmIweGl2QTF2RUtyaUUwak1Wd2lQaz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
    50      server: https://test-cluster-api:6443
    51    name: test1
    52  contexts:
    53  - context:
    54      cluster: test1
    55      user: test1-admin
    56    name: test1-admin@test1
    57  current-context: test1-admin@test1
    58  kind: Config
    59  preferences: {}
    60  users:
    61  - name: test1-admin
    62    user:
    63      client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJUTJFS3c0cU0wbFV3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4T1RBeE1UQXhPREF3TkRCYUZ3MHlNREF4TVRBeE9EQXdOREphTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXUxeWNHcVdLMlZBUGpmWlYKeUdHWmhvQWdxZ1oreVFqU0pYQlVwNkR4VkZyYStENHJDVkNpRDNhWTVmTWNXaVpYVy9uanJsNFRudWJydndhWgpTN0hhMUxELzFZdmhFUFhLcnlBMzVNMStsN0JkUjA3T3NlRnFqNXNJQk9xWDNoNEJmckQ0SFQ5VGxSS082TXgxClMycSt5NzVaYjI5eXN0UTk3SGk4ZXVBS0sxN0JuSmJ5Zk80NlMvOFVxc2tlb0JXT3VnRkJHMlQrTFd6RXluK1oKVjdUUHZxdDE0MG1lQU40TStZUy91dFp2VmE0WFFmKy80czB4TjVwMGw4M0RrYnVWbnErcjR5dzBiSHM4cHdWdwo0Z3RuTVhrbjFhcGUwOGN4YUtBMGpodnZ4cFgyVnhHbEsxUTR0aDk1S2JNQWlpMlVINFcyNE1GSnlxOHloOUljCk54UldZd0lEQVFBQm95Y3dKVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFCbDUwSmNVblhGRHB4TWtkL2JOdlRHMkxVTnVWTVNnQmlCNQpmbFlpWTJibUQ3NVMreEE0eEwrZEYxanlJZHRDTGVtZURoS2MwRWtyVUpyYk5XSTZnVDB0OFAwWVNuYmxiY09ICmxBRHdmMjhoVW5TYTdIR1NOaWNBdDdKOGpnd296ZzFDVnNWbE9YM2cvcWdmSkdYeld0QzJMRFVvdjR3MFVNMVgKQ2pLNFdtMk8xTDFybEpzaHE1VysxalZzTEllYnZIcjlYb0cxRlcyY0ovcHJTK0dFS2dtNWc4YjZ1MWdJQXVFNAozOHNVQTltU3ZBYlgwR1RWdXI3Um9taWhSR2QwTktZK0k1S3A2bWtIRnpLVEVRbks2YXcrQWMvVFJObmFwUEh6Ci9IMXA0eGkyWlFHYi84MURhQjVTZDRwTURzK09FK1BNNitudkN4amN2eFdFbEdTdjE2Yz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
    64      client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBdTF5Y0dxV0syVkFQamZaVnlHR1pob0FncWdaK3lRalNKWEJVcDZEeFZGcmErRDRyCkNWQ2lEM2FZNWZNY1dpWlhXL25qcmw0VG51YnJ2d2FaUzdIYTFMRC8xWXZoRVBYS3J5QTM1TTErbDdCZFIwN08Kc2VGcWo1c0lCT3FYM2g0QmZyRDRIVDlUbFJLTzZNeDFTMnEreTc1WmIyOXlzdFE5N0hpOGV1QUtLMTdCbkpieQpmTzQ2Uy84VXFza2VvQldPdWdGQkcyVCtMV3pFeW4rWlY3VFB2cXQxNDBtZUFONE0rWVMvdXRadlZhNFhRZisvCjRzMHhONXAwbDgzRGtidVZucStyNHl3MGJIczhwd1Z3NGd0bk1Ya24xYXBlMDhjeGFLQTBqaHZ2eHBYMlZ4R2wKSzFRNHRoOTVLYk1BaWkyVUg0VzI0TUZKeXE4eWg5SWNOeFJXWXdJREFRQUJBb0lCQVFDc0JLamw1aHNHemZTWgorQkptT1FXRmNWbU1BUTZpY0ZEUVFzUFdhM05tYVV3bElwN01uSlZOOFNzTDVCcWh3aFh1d2cwQjZDbkhlR2YxCktJL1I2V2JxWTk5ZkpsL3EvRitzVGI1RGVVL0M0UStqQ24zRzN4akE1Q3VHcUFQcTBFMjdEYXVlM3FkVWRJZDAKd1ZMbmZRZlRjOTRVNjVPNUVCZ1NaZjlXS1IvdEZDNHpGSlVselhHTlYxT2hOTWVyeXovbllmSVRZZGppUWNiRwplcDJucHk1cHZ5dEFPY1RiV0xXUEw4T2RKTDMvTER3b0h2aHlSa3huZXhWRTc0K3ZGd2lYbkRkNEp6ODVJVzBvCkFyeGEyRlJzOGZyWXFreHNSQ1VGYmRXNUpMTzhRVFBWYnl3S1c3Z0Z4S0c1U1c4Y004cmJLTHEzT01JOXBXVkoKTzNscVQxc1JBb0dCQU50QUxzR2VodzZsZWN3Zi9VU0RFN0FWNFQrdDJsWit6a3J1d3dodloyWXJYZHpXbGVqTAprNGpZWjhkQUNUUVdDRkJlaWtmYi9XdzZtMFF3ZUZudzExdVd1WndWRVJPS3BnRDFTa0krcVRtdGd0V2J2Y2lBClg4U0t4SU5qTGNzTzRLZUoxdEdkaVVDVEg3MW8zV0pBOXYzR3NaTlkrdW1WTVhnaGQ2d2YrTnB0QW9HQkFOckUKR3djOWNLVGVtZWZWSTcraFVtS2YvNm9SQ2NYdWxIK3gwSEZwNVBIQzl3NEhTMVp0Zk9NS3F6QzlJMWt6a200RwpjYW11WHovRy9iQXg4WGdaa3lURnRxTk5hdjE3Y0UzV25GRlMxejRHeGRQNDMvSkdLVWJrUzhkM1dZc0pkZnRYCkt5Vm45anl3Yjc0VG5hSnFIVlBSWFJRSkNFR3E2VlR4RVVGNlIzSVBBb0dBSmFTYlluckpUV1p6eHV3bkc4QTEKZlNJRWpsNVhBa3E3T0hwTjJnRG1pOUFlU1hBK1JMM1BFc3UwNWF6RTU4QndwUHZXV2dnWE5xSEpUcWZUd2Yxcgp2RG5nbkQreHN0MDNLeXJ5R1BXUk1HbnQ4S2JRcXIvL3NVcngrbXpveTlnK0VnWEVjRERRQTlvK3ROSndVQkkvClZjcnJhaFQ0MzJuU0dJSUdmZkx2VXZFQ2dZQmtNRGVvb3l5NWRQRExTY09yZVhnL2pzTUo0ZSsxNUVQQ0QyOUUKNFpobVdFSEkvUEkxek1MTFFCR1NxcXhMcCtEQjN0V2pQaWFGRU44U0dHMWI4V3FBQnNSVUdacU1LRUlRZzk3bgpKNmRIMHRZNjg5bXNIUkcrVThPWXdFSVQrT3M5aG5oT0UwU2tHckd5UFUyT0drY0FJZndjdHQ0L0pNVGpqOXUxClB3a0ZaUUtCZ1FDTWppdkpGL3crQXlUZUo0K1piWWpvZ091QkJFRE9oeXdiRnN5NC9ubVduTm4rQXRYQklDaGkKR2J6LzFuWkZTOGc2Nlh2cGFTWEQ5blVpS1BOUW5ORzUralJmclluTlI4WERCL3ZiNk9TMVFHbXBvWWxJZ2Q3UgpjTVpSRm1sbTUvbkJMWkdoVVpjOXZVN1pRVis4RXdLK2lHaGNrTFduVGhHNURZTkRWaksxcFE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
    65  `
    66  
    67  	validSecret = &corev1.Secret{
    68  		ObjectMeta: metav1.ObjectMeta{
    69  			Name:      "test1-kubeconfig",
    70  			Namespace: "test",
    71  			Labels:    map[string]string{clusterv1.ClusterNameLabel: "test1"},
    72  		},
    73  		Data: map[string][]byte{
    74  			secret.KubeconfigDataName: []byte(validKubeConfig),
    75  		},
    76  		Type: clusterv1.ClusterSecretType,
    77  	}
    78  )
    79  
    80  func TestGetKubeConfigSecret(t *testing.T) {
    81  	g := NewWithT(t)
    82  
    83  	clusterKey := client.ObjectKey{
    84  		Name:      "test1",
    85  		Namespace: "test",
    86  	}
    87  	// creating a local copy to ensure validSecret.ObjectMeta.ResourceVersion does not get set by fakeClient
    88  	validSec := validSecret.DeepCopy()
    89  	client := fake.NewClientBuilder().WithObjects(validSec).Build()
    90  
    91  	found, err := FromSecret(ctx, client, clusterKey)
    92  	g.Expect(err).ToNot(HaveOccurred())
    93  	g.Expect(found).To(Equal(validSecret.Data[secret.KubeconfigDataName]))
    94  }
    95  
    96  func getTestCACert(key *rsa.PrivateKey) (*x509.Certificate, error) {
    97  	cfg := certs.Config{
    98  		CommonName: "kubernetes",
    99  	}
   100  
   101  	now := time.Now().UTC()
   102  
   103  	tmpl := x509.Certificate{
   104  		SerialNumber: new(big.Int).SetInt64(0),
   105  		Subject: pkix.Name{
   106  			CommonName:   cfg.CommonName,
   107  			Organization: cfg.Organization,
   108  		},
   109  		NotBefore:             now.Add(time.Minute * -5),
   110  		NotAfter:              now.Add(time.Hour * 24), // 1 day
   111  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
   112  		MaxPathLenZero:        true,
   113  		BasicConstraintsValid: true,
   114  		MaxPathLen:            0,
   115  		IsCA:                  true,
   116  	}
   117  
   118  	b, err := x509.CreateCertificate(rand.Reader, &tmpl, &tmpl, key.Public(), key)
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  
   123  	c, err := x509.ParseCertificate(b)
   124  	return c, err
   125  }
   126  
   127  func TestNew(t *testing.T) {
   128  	g := NewWithT(t)
   129  
   130  	testCases := []struct {
   131  		cluster        string
   132  		endpoint       string
   133  		expectedConfig api.Config
   134  		expectError    bool
   135  	}{
   136  		{
   137  			cluster:  "foo",
   138  			endpoint: "https://127:0.0.1:4003",
   139  			expectedConfig: api.Config{
   140  				Clusters: map[string]*api.Cluster{
   141  					"foo": {
   142  						Server: "https://127:0.0.1:4003",
   143  					},
   144  				},
   145  				Contexts: map[string]*api.Context{
   146  					"foo-admin@foo": {
   147  						Cluster:  "foo",
   148  						AuthInfo: "foo-admin",
   149  					},
   150  				},
   151  				CurrentContext: "foo-admin@foo",
   152  			},
   153  			expectError: false,
   154  		},
   155  	}
   156  
   157  	for _, tc := range testCases {
   158  		caKey, err := certs.NewPrivateKey()
   159  		g.Expect(err).ToNot(HaveOccurred())
   160  
   161  		caCert, err := getTestCACert(caKey)
   162  		g.Expect(err).ToNot(HaveOccurred())
   163  
   164  		actualConfig, actualError := New(tc.cluster, tc.endpoint, caCert, caKey)
   165  		if tc.expectError {
   166  			g.Expect(actualError).To(HaveOccurred())
   167  			continue
   168  		}
   169  
   170  		g.Expect(actualConfig.Clusters).To(HaveLen(len(tc.expectedConfig.Clusters)))
   171  		g.Expect(actualConfig.Contexts).To(HaveLen(len(tc.expectedConfig.Contexts)))
   172  
   173  		g.Expect(actualConfig.Clusters[tc.cluster]).NotTo(BeNil())
   174  		g.Expect(actualConfig.Contexts[tc.expectedConfig.CurrentContext]).NotTo(BeNil())
   175  		g.Expect(actualConfig.CurrentContext).To(Equal(tc.expectedConfig.CurrentContext))
   176  		g.Expect(actualConfig.Contexts).To(BeComparableTo(tc.expectedConfig.Contexts))
   177  	}
   178  }
   179  
   180  func TestGenerateSecretWithOwner(t *testing.T) {
   181  	g := NewWithT(t)
   182  
   183  	owner := metav1.OwnerReference{
   184  		Name:       "test1",
   185  		Kind:       "Cluster",
   186  		APIVersion: clusterv1.GroupVersion.String(),
   187  	}
   188  
   189  	expectedSecret := validSecret.DeepCopy()
   190  	expectedSecret.SetOwnerReferences([]metav1.OwnerReference{owner})
   191  
   192  	kubeconfigSecret := GenerateSecretWithOwner(
   193  		client.ObjectKey{
   194  			Name:      "test1",
   195  			Namespace: "test",
   196  		},
   197  		[]byte(validKubeConfig),
   198  		owner,
   199  	)
   200  
   201  	g.Expect(kubeconfigSecret).NotTo(BeNil())
   202  	g.Expect(kubeconfigSecret).To(BeComparableTo(expectedSecret))
   203  }
   204  
   205  func TestGenerateSecret(t *testing.T) {
   206  	g := NewWithT(t)
   207  
   208  	expectedSecret := validSecret.DeepCopy()
   209  	expectedSecret.SetOwnerReferences(
   210  		[]metav1.OwnerReference{
   211  			{
   212  				Name:       "test1",
   213  				Kind:       "Cluster",
   214  				APIVersion: clusterv1.GroupVersion.String(),
   215  			},
   216  		},
   217  	)
   218  
   219  	cluster := &clusterv1.Cluster{}
   220  	cluster.SetNamespace("test")
   221  	cluster.SetName("test1")
   222  
   223  	kubeconfigSecret := GenerateSecret(
   224  		cluster,
   225  		[]byte(validKubeConfig),
   226  	)
   227  
   228  	g.Expect(kubeconfigSecret).NotTo(BeNil())
   229  	g.Expect(kubeconfigSecret).To(Equal(expectedSecret))
   230  }
   231  
   232  func TestCreateSecretWithOwner(t *testing.T) {
   233  	g := NewWithT(t)
   234  
   235  	caKey, err := certs.NewPrivateKey()
   236  	g.Expect(err).ToNot(HaveOccurred())
   237  
   238  	caCert, err := getTestCACert(caKey)
   239  	g.Expect(err).ToNot(HaveOccurred())
   240  
   241  	caSecret := &corev1.Secret{
   242  		ObjectMeta: metav1.ObjectMeta{
   243  			Name:      "test1-ca",
   244  			Namespace: "test",
   245  		},
   246  		Data: map[string][]byte{
   247  			secret.TLSKeyDataName: certs.EncodePrivateKeyPEM(caKey),
   248  			secret.TLSCrtDataName: certs.EncodeCertPEM(caCert),
   249  		},
   250  	}
   251  
   252  	c := fake.NewClientBuilder().WithObjects(caSecret).Build()
   253  
   254  	owner := metav1.OwnerReference{
   255  		Name:       "test1",
   256  		Kind:       "Cluster",
   257  		APIVersion: clusterv1.GroupVersion.String(),
   258  	}
   259  
   260  	err = CreateSecretWithOwner(
   261  		ctx,
   262  		c,
   263  		client.ObjectKey{
   264  			Name:      "test1",
   265  			Namespace: "test",
   266  		},
   267  		"localhost:6443",
   268  		owner,
   269  	)
   270  
   271  	g.Expect(err).ToNot(HaveOccurred())
   272  
   273  	s := &corev1.Secret{}
   274  	key := client.ObjectKey{Name: "test1-kubeconfig", Namespace: "test"}
   275  	g.Expect(c.Get(ctx, key, s)).To(Succeed())
   276  	g.Expect(s.OwnerReferences).To(ContainElement(owner))
   277  	g.Expect(s.Type).To(Equal(clusterv1.ClusterSecretType))
   278  
   279  	clientConfig, err := clientcmd.NewClientConfigFromBytes(s.Data[secret.KubeconfigDataName])
   280  	g.Expect(err).ToNot(HaveOccurred())
   281  	restClient, err := clientConfig.ClientConfig()
   282  	g.Expect(err).ToNot(HaveOccurred())
   283  	g.Expect(restClient.CAData).To(Equal(certs.EncodeCertPEM(caCert)))
   284  	g.Expect(restClient.Host).To(Equal("https://localhost:6443"))
   285  }
   286  
   287  func TestCreateSecret(t *testing.T) {
   288  	g := NewWithT(t)
   289  
   290  	caKey, err := certs.NewPrivateKey()
   291  	g.Expect(err).ToNot(HaveOccurred())
   292  
   293  	caCert, err := getTestCACert(caKey)
   294  	g.Expect(err).ToNot(HaveOccurred())
   295  
   296  	caSecret := &corev1.Secret{
   297  		ObjectMeta: metav1.ObjectMeta{
   298  			Name:      "test1-ca",
   299  			Namespace: "test",
   300  		},
   301  		Data: map[string][]byte{
   302  			secret.TLSKeyDataName: certs.EncodePrivateKeyPEM(caKey),
   303  			secret.TLSCrtDataName: certs.EncodeCertPEM(caCert),
   304  		},
   305  	}
   306  
   307  	c := fake.NewClientBuilder().WithObjects(caSecret).Build()
   308  
   309  	cluster := &clusterv1.Cluster{
   310  		ObjectMeta: metav1.ObjectMeta{
   311  			Name:      "test1",
   312  			Namespace: "test",
   313  		},
   314  		Spec: clusterv1.ClusterSpec{
   315  			ControlPlaneEndpoint: clusterv1.APIEndpoint{
   316  				Host: "localhost",
   317  				Port: 8443,
   318  			},
   319  		},
   320  	}
   321  
   322  	err = CreateSecret(
   323  		ctx,
   324  		c,
   325  		cluster,
   326  	)
   327  
   328  	g.Expect(err).ToNot(HaveOccurred())
   329  
   330  	s := &corev1.Secret{}
   331  	key := client.ObjectKey{Name: "test1-kubeconfig", Namespace: "test"}
   332  	g.Expect(c.Get(ctx, key, s)).To(Succeed())
   333  	g.Expect(s.OwnerReferences).To(ContainElement(
   334  		metav1.OwnerReference{
   335  			Name:       cluster.Name,
   336  			Kind:       "Cluster",
   337  			APIVersion: clusterv1.GroupVersion.String(),
   338  		},
   339  	))
   340  	g.Expect(s.Type).To(Equal(clusterv1.ClusterSecretType))
   341  
   342  	clientConfig, err := clientcmd.NewClientConfigFromBytes(s.Data[secret.KubeconfigDataName])
   343  	g.Expect(err).ToNot(HaveOccurred())
   344  	restClient, err := clientConfig.ClientConfig()
   345  	g.Expect(err).ToNot(HaveOccurred())
   346  	g.Expect(restClient.CAData).To(Equal(certs.EncodeCertPEM(caCert)))
   347  	g.Expect(restClient.Host).To(Equal("https://localhost:8443"))
   348  }
   349  
   350  func TestNeedsClientCertRotation(t *testing.T) {
   351  	g := NewWithT(t)
   352  	caKey, err := certs.NewPrivateKey()
   353  	g.Expect(err).ToNot(HaveOccurred())
   354  
   355  	caCert, err := getTestCACert(caKey)
   356  	g.Expect(err).ToNot(HaveOccurred())
   357  
   358  	config, err := New("foo", "https://127:0.0.1:4003", caCert, caKey)
   359  	g.Expect(err).ToNot(HaveOccurred())
   360  
   361  	out, err := clientcmd.Write(*config)
   362  	g.Expect(err).ToNot(HaveOccurred())
   363  
   364  	owner := metav1.OwnerReference{
   365  		Name:       "test1",
   366  		Kind:       "Cluster",
   367  		APIVersion: clusterv1.GroupVersion.String(),
   368  	}
   369  
   370  	kubeconfigSecret := GenerateSecretWithOwner(
   371  		client.ObjectKey{
   372  			Name:      "test1",
   373  			Namespace: "test",
   374  		},
   375  		out,
   376  		owner,
   377  	)
   378  
   379  	g.Expect(NeedsClientCertRotation(kubeconfigSecret, certs.DefaultCertDuration)).To(BeTrue())
   380  	g.Expect(NeedsClientCertRotation(kubeconfigSecret, certs.DefaultCertDuration-time.Hour)).To(BeFalse())
   381  }
   382  
   383  func TestRegenerateClientCerts(t *testing.T) {
   384  	g := NewWithT(t)
   385  	caKey, err := certs.NewPrivateKey()
   386  	g.Expect(err).ToNot(HaveOccurred())
   387  
   388  	caCert, err := getTestCACert(caKey)
   389  	g.Expect(err).ToNot(HaveOccurred())
   390  
   391  	caSecret := &corev1.Secret{
   392  		ObjectMeta: metav1.ObjectMeta{
   393  			Name:      "test1-ca",
   394  			Namespace: "test",
   395  		},
   396  		Data: map[string][]byte{
   397  			secret.TLSKeyDataName: certs.EncodePrivateKeyPEM(caKey),
   398  			secret.TLSCrtDataName: certs.EncodeCertPEM(caCert),
   399  		},
   400  	}
   401  
   402  	c := fake.NewClientBuilder().WithObjects(validSecret, caSecret).Build()
   403  
   404  	oldConfig, err := clientcmd.Load(validSecret.Data[secret.KubeconfigDataName])
   405  	g.Expect(err).ToNot(HaveOccurred())
   406  	oldCert, err := certs.DecodeCertPEM(oldConfig.AuthInfos["test1-admin"].ClientCertificateData)
   407  	g.Expect(err).ToNot(HaveOccurred())
   408  
   409  	g.Expect(RegenerateSecret(ctx, c, validSecret)).To(Succeed())
   410  
   411  	newSecret := &corev1.Secret{}
   412  	g.Expect(c.Get(ctx, util.ObjectKey(validSecret), newSecret)).To(Succeed())
   413  	newConfig, err := clientcmd.Load(newSecret.Data[secret.KubeconfigDataName])
   414  	g.Expect(err).ToNot(HaveOccurred())
   415  	newCert, err := certs.DecodeCertPEM(newConfig.AuthInfos["test1-admin"].ClientCertificateData)
   416  	g.Expect(err).ToNot(HaveOccurred())
   417  
   418  	g.Expect(newCert.NotAfter).To(BeTemporally(">", oldCert.NotAfter))
   419  }