k8s.io/client-go@v0.31.1/util/certificate/certificate_store_test.go (about) 1 /* 2 Copyright 2017 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 certificate 18 19 import ( 20 "bytes" 21 "os" 22 "path/filepath" 23 "testing" 24 ) 25 26 func TestUpdateSymlinkExistingFileError(t *testing.T) { 27 dir, err := os.MkdirTemp("", "k8s-test-update-symlink") 28 if err != nil { 29 t.Fatalf("Unable to create the test directory %q: %v", dir, err) 30 } 31 defer func() { 32 if err := os.RemoveAll(dir); err != nil { 33 t.Errorf("Unable to clean up test directory %q: %v", dir, err) 34 } 35 }() 36 pairFile := filepath.Join(dir, "kubelet-current.pem") 37 if err := os.WriteFile(pairFile, nil, 0600); err != nil { 38 t.Fatalf("Unable to create the file %q: %v", pairFile, err) 39 } 40 41 s := fileStore{ 42 certDirectory: dir, 43 pairNamePrefix: "kubelet", 44 } 45 if err := s.updateSymlink(pairFile); err == nil { 46 t.Errorf("Got no error, wanted to fail updating the symlink because there is a file there.") 47 } 48 } 49 50 func TestUpdateSymlinkNewFileNotExist(t *testing.T) { 51 dir, err := os.MkdirTemp("", "k8s-test-update-symlink") 52 if err != nil { 53 t.Fatalf("Unable to create the test directory %q: %v", dir, err) 54 } 55 defer func() { 56 if err := os.RemoveAll(dir); err != nil { 57 t.Errorf("Unable to clean up test directory %q: %v", dir, err) 58 } 59 }() 60 oldPairFile := filepath.Join(dir, "kubelet-oldpair.pem") 61 if err := os.WriteFile(oldPairFile, nil, 0600); err != nil { 62 t.Fatalf("Unable to create the file %q: %v", oldPairFile, err) 63 } 64 65 s := fileStore{ 66 certDirectory: dir, 67 pairNamePrefix: "kubelet", 68 } 69 if err := s.updateSymlink(oldPairFile); err != nil { 70 t.Errorf("Got error %v, wanted successful update of the symlink to point to %q", err, oldPairFile) 71 } 72 73 if _, err := os.Stat(oldPairFile); err != nil { 74 t.Errorf("Got error %v, wanted file %q to be there.", err, oldPairFile) 75 } 76 77 currentPairFile := filepath.Join(dir, "kubelet-current.pem") 78 if fi, err := os.Lstat(currentPairFile); err != nil { 79 t.Errorf("Got error %v, wanted file %q to be there", err, currentPairFile) 80 } else if fi.Mode()&os.ModeSymlink != os.ModeSymlink { 81 t.Errorf("Got %q not a symlink.", currentPairFile) 82 } 83 84 newPairFile := filepath.Join(dir, "kubelet-newpair.pem") 85 if err := s.updateSymlink(newPairFile); err == nil { 86 t.Errorf("Got no error, wanted to fail updating the symlink the file %q does not exist.", newPairFile) 87 } 88 } 89 90 func TestUpdateSymlinkNoSymlink(t *testing.T) { 91 dir, err := os.MkdirTemp("", "k8s-test-update-symlink") 92 if err != nil { 93 t.Fatalf("Unable to create the test directory %q: %v", dir, err) 94 } 95 defer func() { 96 if err := os.RemoveAll(dir); err != nil { 97 t.Errorf("Unable to clean up test directory %q: %v", dir, err) 98 } 99 }() 100 pairFile := filepath.Join(dir, "kubelet-newfile.pem") 101 if err := os.WriteFile(pairFile, nil, 0600); err != nil { 102 t.Fatalf("Unable to create the file %q: %v", pairFile, err) 103 } 104 105 s := fileStore{ 106 certDirectory: dir, 107 pairNamePrefix: "kubelet", 108 } 109 if err := s.updateSymlink(pairFile); err != nil { 110 t.Errorf("Got error %v, wanted a new symlink to be created", err) 111 } 112 113 if _, err := os.Stat(pairFile); err != nil { 114 t.Errorf("Got error %v, wanted file %q to be there", err, pairFile) 115 } 116 currentPairFile := filepath.Join(dir, "kubelet-current.pem") 117 if fi, err := os.Lstat(currentPairFile); err != nil { 118 t.Errorf("Got %v, wanted %q to be there", currentPairFile, err) 119 } else if fi.Mode()&os.ModeSymlink != os.ModeSymlink { 120 t.Errorf("%q not a symlink, wanted a symlink.", currentPairFile) 121 } 122 } 123 124 func TestUpdateSymlinkReplaceExistingSymlink(t *testing.T) { 125 prefix := "kubelet" 126 dir, err := os.MkdirTemp("", "k8s-test-update-symlink") 127 if err != nil { 128 t.Fatalf("Unable to create the test directory %q: %v", dir, err) 129 } 130 defer func() { 131 if err := os.RemoveAll(dir); err != nil { 132 t.Errorf("Unable to clean up test directory %q: %v", dir, err) 133 } 134 }() 135 oldPairFile := filepath.Join(dir, prefix+"-oldfile.pem") 136 if err := os.WriteFile(oldPairFile, nil, 0600); err != nil { 137 t.Fatalf("Unable to create the file %q: %v", oldPairFile, err) 138 } 139 newPairFile := filepath.Join(dir, prefix+"-newfile.pem") 140 if err := os.WriteFile(newPairFile, nil, 0600); err != nil { 141 t.Fatalf("Unable to create the file %q: %v", newPairFile, err) 142 } 143 currentPairFile := filepath.Join(dir, prefix+"-current.pem") 144 if err := os.Symlink(oldPairFile, currentPairFile); err != nil { 145 t.Fatalf("unable to create a symlink from %q to %q: %v", currentPairFile, oldPairFile, err) 146 } 147 if resolved, err := os.Readlink(currentPairFile); err != nil { 148 t.Fatalf("Got %v when attempting to resolve symlink %q", err, currentPairFile) 149 } else if resolved != oldPairFile { 150 t.Fatalf("Got %q as resolution of symlink %q, wanted %q", resolved, currentPairFile, oldPairFile) 151 } 152 153 s := fileStore{ 154 certDirectory: dir, 155 pairNamePrefix: prefix, 156 } 157 if err := s.updateSymlink(newPairFile); err != nil { 158 t.Errorf("Got error %v, wanted a new symlink to be created", err) 159 } 160 161 if _, err := os.Stat(oldPairFile); err != nil { 162 t.Errorf("Got error %v, wanted file %q to be there", oldPairFile, err) 163 } 164 if _, err := os.Stat(newPairFile); err != nil { 165 t.Errorf("Got error %v, wanted file %q to be there", newPairFile, err) 166 } 167 if fi, err := os.Lstat(currentPairFile); err != nil { 168 t.Errorf("Got %v, wanted %q to be there", currentPairFile, err) 169 } else if fi.Mode()&os.ModeSymlink != os.ModeSymlink { 170 t.Errorf("%q not a symlink, wanted a symlink.", currentPairFile) 171 } 172 if resolved, err := os.Readlink(currentPairFile); err != nil { 173 t.Fatalf("Got %v when attempting to resolve symlink %q", err, currentPairFile) 174 } else if resolved != newPairFile { 175 t.Fatalf("Got %q as resolution of symlink %q, wanted %q", resolved, currentPairFile, newPairFile) 176 } 177 } 178 179 func TestLoadFile(t *testing.T) { 180 dir, err := os.MkdirTemp("", "k8s-test-load-cert-key-blocks") 181 if err != nil { 182 t.Fatalf("Unable to create the test directory %q: %v", dir, err) 183 } 184 defer func() { 185 if err := os.RemoveAll(dir); err != nil { 186 t.Errorf("Unable to clean up test directory %q: %v", dir, err) 187 } 188 }() 189 190 pairFile := filepath.Join(dir, "kubelet-pair.pem") 191 192 tests := []struct { 193 desc string 194 data []byte 195 }{ 196 {desc: "cert and key", data: bytes.Join([][]byte{storeCertData.certificatePEM, storeCertData.keyPEM}, []byte("\n"))}, 197 {desc: "key and cert", data: bytes.Join([][]byte{storeCertData.keyPEM, storeCertData.certificatePEM}, []byte("\n"))}, 198 } 199 for _, tt := range tests { 200 t.Run(tt.desc, func(t *testing.T) { 201 if err := os.WriteFile(pairFile, tt.data, 0600); err != nil { 202 t.Fatalf("Unable to create the file %q: %v", pairFile, err) 203 } 204 cert, err := loadFile(pairFile) 205 if err != nil { 206 t.Fatalf("Could not load certificate from disk: %v", err) 207 } 208 if cert == nil { 209 t.Fatalf("There was no error, but no certificate data was returned.") 210 } 211 if cert.Leaf == nil { 212 t.Fatalf("Got an empty leaf, expected private data.") 213 } 214 }) 215 } 216 } 217 218 func TestUpdateNoRotation(t *testing.T) { 219 prefix := "kubelet-server" 220 dir, err := os.MkdirTemp("", "k8s-test-certstore-current") 221 if err != nil { 222 t.Fatalf("Unable to create the test directory %q: %v", dir, err) 223 } 224 defer func() { 225 if err := os.RemoveAll(dir); err != nil { 226 t.Errorf("Unable to clean up test directory %q: %v", dir, err) 227 } 228 }() 229 keyFile := filepath.Join(dir, "kubelet.key") 230 if err := os.WriteFile(keyFile, storeCertData.keyPEM, 0600); err != nil { 231 t.Fatalf("Unable to create the file %q: %v", keyFile, err) 232 } 233 certFile := filepath.Join(dir, "kubelet.crt") 234 if err := os.WriteFile(certFile, storeCertData.certificatePEM, 0600); err != nil { 235 t.Fatalf("Unable to create the file %q: %v", certFile, err) 236 } 237 238 s, err := NewFileStore(prefix, dir, dir, certFile, keyFile) 239 if err != nil { 240 t.Fatalf("Got %v while creating a new store.", err) 241 } 242 243 cert, err := s.Update(storeCertData.certificatePEM, storeCertData.keyPEM) 244 if err != nil { 245 t.Errorf("Got %v while updating certificate store.", err) 246 } 247 if cert == nil { 248 t.Errorf("Got nil certificate, expected something real.") 249 } 250 } 251 252 func TestUpdateRotation(t *testing.T) { 253 prefix := "kubelet-server" 254 dir, err := os.MkdirTemp("", "k8s-test-certstore-current") 255 if err != nil { 256 t.Fatalf("Unable to create the test directory %q: %v", dir, err) 257 } 258 defer func() { 259 if err := os.RemoveAll(dir); err != nil { 260 t.Errorf("Unable to clean up test directory %q: %v", dir, err) 261 } 262 }() 263 keyFile := filepath.Join(dir, "kubelet.key") 264 if err := os.WriteFile(keyFile, storeCertData.keyPEM, 0600); err != nil { 265 t.Fatalf("Unable to create the file %q: %v", keyFile, err) 266 } 267 certFile := filepath.Join(dir, "kubelet.crt") 268 if err := os.WriteFile(certFile, storeCertData.certificatePEM, 0600); err != nil { 269 t.Fatalf("Unable to create the file %q: %v", certFile, err) 270 } 271 272 s, err := NewFileStore(prefix, dir, dir, certFile, keyFile) 273 if err != nil { 274 t.Fatalf("Got %v while creating a new store.", err) 275 } 276 277 cert, err := s.Update(storeCertData.certificatePEM, storeCertData.keyPEM) 278 if err != nil { 279 t.Fatalf("Got %v while updating certificate store.", err) 280 } 281 if cert == nil { 282 t.Fatalf("Got nil certificate, expected something real.") 283 } 284 } 285 286 func TestUpdateTwoCerts(t *testing.T) { 287 prefix := "kubelet-server" 288 dir, err := os.MkdirTemp("", "k8s-test-certstore-current") 289 if err != nil { 290 t.Fatalf("Unable to create the test directory %q: %v", dir, err) 291 } 292 defer func() { 293 if err := os.RemoveAll(dir); err != nil { 294 t.Errorf("Unable to clean up test directory %q: %v", dir, err) 295 } 296 }() 297 keyFile := filepath.Join(dir, "kubelet.key") 298 if err := os.WriteFile(keyFile, storeTwoCertsData.keyPEM, 0600); err != nil { 299 t.Fatalf("Unable to create the file %q: %v", keyFile, err) 300 } 301 certFile := filepath.Join(dir, "kubelet.crt") 302 if err := os.WriteFile(certFile, storeTwoCertsData.certificatePEM, 0600); err != nil { 303 t.Fatalf("Unable to create the file %q: %v", certFile, err) 304 } 305 306 s, err := NewFileStore(prefix, dir, dir, certFile, keyFile) 307 if err != nil { 308 t.Fatalf("Got %v while creating a new store.", err) 309 } 310 311 cert, err := s.Update(storeTwoCertsData.certificatePEM, storeTwoCertsData.keyPEM) 312 if err != nil { 313 t.Errorf("Got %v while updating certificate store.", err) 314 } 315 if cert == nil { 316 t.Fatalf("Got nil certificate, expected something real.") 317 } 318 if len(cert.Certificate) != 2 { 319 t.Fatalf("Unexpected number of certificates, expected 2, got %v", len(cert.Certificate)) 320 } 321 } 322 323 func TestUpdateWithBadCertKeyData(t *testing.T) { 324 prefix := "kubelet-server" 325 dir, err := os.MkdirTemp("", "k8s-test-certstore-current") 326 if err != nil { 327 t.Fatalf("Unable to create the test directory %q: %v", dir, err) 328 } 329 defer func() { 330 if err := os.RemoveAll(dir); err != nil { 331 t.Errorf("Unable to clean up test directory %q: %v", dir, err) 332 } 333 }() 334 keyFile := filepath.Join(dir, "kubelet.key") 335 if err := os.WriteFile(keyFile, storeCertData.keyPEM, 0600); err != nil { 336 t.Fatalf("Unable to create the file %q: %v", keyFile, err) 337 } 338 certFile := filepath.Join(dir, "kubelet.crt") 339 if err := os.WriteFile(certFile, storeCertData.certificatePEM, 0600); err != nil { 340 t.Fatalf("Unable to create the file %q: %v", certFile, err) 341 } 342 343 s, err := NewFileStore(prefix, dir, dir, certFile, keyFile) 344 if err != nil { 345 t.Fatalf("Got %v while creating a new store.", err) 346 } 347 348 cert, err := s.Update([]byte{0, 0}, storeCertData.keyPEM) 349 if err == nil { 350 t.Fatalf("Got no error while updating certificate store with invalid data.") 351 } 352 if cert != nil { 353 t.Fatalf("Got %v certificate returned from the update, expected nil.", cert) 354 } 355 } 356 357 func TestCurrentPairFile(t *testing.T) { 358 prefix := "kubelet-server" 359 dir, err := os.MkdirTemp("", "k8s-test-certstore-current") 360 if err != nil { 361 t.Fatalf("Unable to create the test directory %q: %v", dir, err) 362 } 363 defer func() { 364 if err := os.RemoveAll(dir); err != nil { 365 t.Errorf("Unable to clean up test directory %q: %v", dir, err) 366 } 367 }() 368 pairFile := filepath.Join(dir, prefix+"-pair.pem") 369 data := append(storeCertData.certificatePEM, []byte("\n")...) 370 data = append(data, storeCertData.keyPEM...) 371 if err := os.WriteFile(pairFile, data, 0600); err != nil { 372 t.Fatalf("Unable to create the file %q: %v", pairFile, err) 373 } 374 currentFile := filepath.Join(dir, prefix+"-current.pem") 375 if err := os.Symlink(pairFile, currentFile); err != nil { 376 t.Fatalf("unable to create a symlink from %q to %q: %v", currentFile, pairFile, err) 377 } 378 379 store, err := NewFileStore("kubelet-server", dir, dir, "", "") 380 if err != nil { 381 t.Fatalf("Failed to initialize certificate store: %v", err) 382 } 383 384 cert, err := store.Current() 385 if err != nil { 386 t.Fatalf("Could not load certificate from disk: %v", err) 387 } 388 if cert == nil { 389 t.Fatalf("There was no error, but no certificate data was returned.") 390 } 391 if cert.Leaf == nil { 392 t.Fatalf("Got an empty leaf, expected private data.") 393 } 394 } 395 396 func TestCurrentCertKeyFiles(t *testing.T) { 397 prefix := "kubelet-server" 398 dir, err := os.MkdirTemp("", "k8s-test-certstore-current") 399 if err != nil { 400 t.Fatalf("Unable to create the test directory %q: %v", dir, err) 401 } 402 defer func() { 403 if err := os.RemoveAll(dir); err != nil { 404 t.Errorf("Unable to clean up test directory %q: %v", dir, err) 405 } 406 }() 407 certFile := filepath.Join(dir, "kubelet.crt") 408 if err := os.WriteFile(certFile, storeCertData.certificatePEM, 0600); err != nil { 409 t.Fatalf("Unable to create the file %q: %v", certFile, err) 410 } 411 keyFile := filepath.Join(dir, "kubelet.key") 412 if err := os.WriteFile(keyFile, storeCertData.keyPEM, 0600); err != nil { 413 t.Fatalf("Unable to create the file %q: %v", keyFile, err) 414 } 415 416 store, err := NewFileStore(prefix, dir, dir, certFile, keyFile) 417 if err != nil { 418 t.Fatalf("Failed to initialize certificate store: %v", err) 419 } 420 421 cert, err := store.Current() 422 if err != nil { 423 t.Fatalf("Could not load certificate from disk: %v", err) 424 } 425 if cert == nil { 426 t.Fatalf("There was no error, but no certificate data was returned.") 427 } 428 if cert.Leaf == nil { 429 t.Fatalf("Got an empty leaf, expected private data.") 430 } 431 } 432 433 func TestCurrentTwoCerts(t *testing.T) { 434 prefix := "kubelet-server" 435 dir, err := os.MkdirTemp("", "k8s-test-certstore-current") 436 if err != nil { 437 t.Fatalf("Unable to create the test directory %q: %v", dir, err) 438 } 439 defer func() { 440 if err := os.RemoveAll(dir); err != nil { 441 t.Errorf("Unable to clean up test directory %q: %v", dir, err) 442 } 443 }() 444 certFile := filepath.Join(dir, "kubelet.crt") 445 if err := os.WriteFile(certFile, storeTwoCertsData.certificatePEM, 0600); err != nil { 446 t.Fatalf("Unable to create the file %q: %v", certFile, err) 447 } 448 keyFile := filepath.Join(dir, "kubelet.key") 449 if err := os.WriteFile(keyFile, storeTwoCertsData.keyPEM, 0600); err != nil { 450 t.Fatalf("Unable to create the file %q: %v", keyFile, err) 451 } 452 453 store, err := NewFileStore(prefix, dir, dir, certFile, keyFile) 454 if err != nil { 455 t.Fatalf("Failed to initialize certificate store: %v", err) 456 } 457 458 cert, err := store.Current() 459 if err != nil { 460 t.Fatalf("Could not load certificate from disk: %v", err) 461 } 462 if cert == nil { 463 t.Fatalf("There was no error, but no certificate data was returned.") 464 } 465 if cert.Leaf == nil { 466 t.Fatalf("Got an empty leaf, expected private data.") 467 } 468 if len(cert.Certificate) != 2 { 469 t.Fatalf("Unexpected number of certificates, expected 2, got %v", len(cert.Certificate)) 470 } 471 } 472 473 func TestCurrentNoFiles(t *testing.T) { 474 dir, err := os.MkdirTemp("", "k8s-test-certstore-current") 475 if err != nil { 476 t.Fatalf("Unable to create the test directory %q: %v", dir, err) 477 } 478 defer func() { 479 if err := os.RemoveAll(dir); err != nil { 480 t.Errorf("Unable to clean up test directory %q: %v", dir, err) 481 } 482 }() 483 484 store, err := NewFileStore("kubelet-server", dir, dir, "", "") 485 if err != nil { 486 t.Fatalf("Failed to initialize certificate store: %v", err) 487 } 488 489 cert, err := store.Current() 490 if err == nil { 491 t.Fatalf("Got no error, expected an error because the cert/key files don't exist.") 492 } 493 if _, ok := err.(*NoCertKeyError); !ok { 494 t.Fatalf("Got error %v, expected NoCertKeyError.", err) 495 } 496 if cert != nil { 497 t.Fatalf("Got certificate, expected no certificate because the cert/key files don't exist.") 498 } 499 }