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