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  }