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 }