...

Source file src/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal/readwriter_test.go

Documentation: k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal

     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 renewal
    18  
    19  import (
    20  	"crypto"
    21  	"crypto/x509"
    22  	"fmt"
    23  	"net"
    24  	"os"
    25  	"path/filepath"
    26  	"testing"
    27  
    28  	"k8s.io/client-go/tools/clientcmd"
    29  	certutil "k8s.io/client-go/util/cert"
    30  	"k8s.io/client-go/util/keyutil"
    31  	netutils "k8s.io/utils/net"
    32  
    33  	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
    34  	kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
    35  	"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
    36  	testutil "k8s.io/kubernetes/cmd/kubeadm/test"
    37  )
    38  
    39  func TestPKICertificateReadWriter(t *testing.T) {
    40  	// creates a tmp folder
    41  	dir := testutil.SetupTempDir(t)
    42  	defer os.RemoveAll(dir)
    43  
    44  	// creates a certificate
    45  	cert := writeTestCertificate(t, dir, "test", testCACert, testCAKey, testCertOrganization)
    46  
    47  	// Creates a pkiCertificateReadWriter
    48  	pkiReadWriter := newPKICertificateReadWriter(dir, "test")
    49  
    50  	// Reads the certificate
    51  	readCert, err := pkiReadWriter.Read()
    52  	if err != nil {
    53  		t.Fatalf("couldn't read certificate: %v", err)
    54  	}
    55  
    56  	// Check if the certificate read from disk is equal to the original one
    57  	if !cert.Equal(readCert) {
    58  		t.Errorf("read cert does not match with expected cert")
    59  	}
    60  
    61  	// Create a new cert
    62  	newCert, newkey, err := pkiutil.NewCertAndKey(testCACert, testCAKey, testCertCfg)
    63  	if err != nil {
    64  		t.Fatalf("couldn't generate certificate: %v", err)
    65  	}
    66  
    67  	// Writes the new certificate
    68  	err = pkiReadWriter.Write(newCert, newkey)
    69  	if err != nil {
    70  		t.Fatalf("couldn't write new certificate: %v", err)
    71  	}
    72  
    73  	// Reads back the new certificate
    74  	readCert, err = pkiReadWriter.Read()
    75  	if err != nil {
    76  		t.Fatalf("couldn't read new certificate: %v", err)
    77  	}
    78  
    79  	// Check if the new certificate read from disk is equal to the original one
    80  	if !newCert.Equal(readCert) {
    81  		t.Error("read cert does not match with expected new cert")
    82  	}
    83  }
    84  
    85  func TestKubeconfigReadWriter(t *testing.T) {
    86  	// creates tmp folders
    87  	dirKubernetes := testutil.SetupTempDir(t)
    88  	defer os.RemoveAll(dirKubernetes)
    89  	dirPKI := testutil.SetupTempDir(t)
    90  	defer os.RemoveAll(dirPKI)
    91  
    92  	// write the CA cert and key to the temporary PKI dir
    93  	caName := kubeadmconstants.CACertAndKeyBaseName
    94  	if err := pkiutil.WriteCertAndKey(
    95  		dirPKI,
    96  		caName,
    97  		testCACert,
    98  		testCAKey); err != nil {
    99  		t.Fatalf("couldn't write out certificate %s to %s", caName, dirPKI)
   100  	}
   101  
   102  	// creates a certificate and then embeds it into a kubeconfig file
   103  	cert := writeTestKubeconfig(t, dirKubernetes, "test", testCACert, testCAKey)
   104  
   105  	// Creates a KubeconfigReadWriter
   106  	kubeconfigReadWriter := newKubeconfigReadWriter(dirKubernetes, "test", dirPKI, caName)
   107  
   108  	// Reads the certificate embedded in a kubeconfig
   109  	readCert, err := kubeconfigReadWriter.Read()
   110  	if err != nil {
   111  		t.Fatalf("couldn't read embedded certificate: %v", err)
   112  	}
   113  
   114  	// Check if the certificate read from disk is equal to the original one
   115  	if !cert.Equal(readCert) {
   116  		t.Errorf("read cert does not match with expected cert")
   117  	}
   118  
   119  	// Create a new cert
   120  	newCert, newkey, err := pkiutil.NewCertAndKey(testCACert, testCAKey, testCertCfg)
   121  	if err != nil {
   122  		t.Fatalf("couldn't generate certificate: %v", err)
   123  	}
   124  
   125  	// Writes the new certificate embedded in a kubeconfig
   126  	err = kubeconfigReadWriter.Write(newCert, newkey)
   127  	if err != nil {
   128  		t.Fatalf("couldn't write new embedded certificate: %v", err)
   129  	}
   130  
   131  	// Make sure that CA key is not present during Read() as it is not needed.
   132  	// This covers testing when the CA is external and not present on the host.
   133  	_, caKeyPath := pkiutil.PathsForCertAndKey(dirPKI, caName)
   134  	os.Remove(caKeyPath)
   135  
   136  	// Reads back the new certificate embedded in a kubeconfig writer
   137  	readCert, err = kubeconfigReadWriter.Read()
   138  	if err != nil {
   139  		t.Fatalf("couldn't read new embedded  certificate: %v", err)
   140  	}
   141  
   142  	// Check if the new certificate read from disk is equal to the original one
   143  	if !newCert.Equal(readCert) {
   144  		t.Errorf("read cert does not match with expected new cert")
   145  	}
   146  }
   147  
   148  // writeTestCertificate is a utility for creating a test certificate
   149  func writeTestCertificate(t *testing.T, dir, name string, caCert *x509.Certificate, caKey crypto.Signer, organization []string) *x509.Certificate {
   150  	cert, key, err := pkiutil.NewCertAndKey(caCert, caKey, makeTestCertConfig(organization))
   151  	if err != nil {
   152  		t.Fatalf("couldn't generate certificate: %v", err)
   153  	}
   154  
   155  	if err := pkiutil.WriteCertAndKey(dir, name, cert, key); err != nil {
   156  		t.Fatalf("couldn't write out certificate %s to %s", name, dir)
   157  	}
   158  
   159  	return cert
   160  }
   161  
   162  // writeTestKubeconfig is a utility for creating a test kubeconfig with an embedded certificate
   163  func writeTestKubeconfig(t *testing.T, dir, name string, caCert *x509.Certificate, caKey crypto.Signer) *x509.Certificate {
   164  
   165  	cfg := &pkiutil.CertConfig{
   166  		Config: certutil.Config{
   167  			CommonName:   "test-common-name",
   168  			Organization: testCertOrganization,
   169  			Usages:       []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
   170  			AltNames: certutil.AltNames{
   171  				IPs:      []net.IP{netutils.ParseIPSloppy("10.100.0.1")},
   172  				DNSNames: []string{"test-domain.space"},
   173  			},
   174  		},
   175  	}
   176  	cert, key, err := pkiutil.NewCertAndKey(caCert, caKey, cfg)
   177  	if err != nil {
   178  		t.Fatalf("couldn't generate certificate: %v", err)
   179  	}
   180  
   181  	encodedClientKey, err := keyutil.MarshalPrivateKeyToPEM(key)
   182  	if err != nil {
   183  		t.Fatalf("failed to marshal private key to PEM: %v", err)
   184  	}
   185  
   186  	certificateAuthorityData := pkiutil.EncodeCertPEM(caCert)
   187  
   188  	config := kubeconfigutil.CreateWithCerts(
   189  		"https://localhost:1234",
   190  		"kubernetes-test",
   191  		"user-test",
   192  		certificateAuthorityData,
   193  		encodedClientKey,
   194  		pkiutil.EncodeCertPEM(cert),
   195  	)
   196  
   197  	if err := clientcmd.WriteToFile(*config, filepath.Join(dir, name)); err != nil {
   198  		t.Fatalf("couldn't write out certificate")
   199  	}
   200  
   201  	return cert
   202  }
   203  
   204  func TestFileExists(t *testing.T) {
   205  	tmpdir, err := os.MkdirTemp("", "")
   206  	if err != nil {
   207  		t.Fatalf("Couldn't create tmpdir: %v", err)
   208  	}
   209  	defer func() {
   210  		err = os.RemoveAll(tmpdir)
   211  		if err != nil {
   212  			t.Fatalf("Fail to remove tmpdir: %v", err)
   213  		}
   214  	}()
   215  	tmpfile, err := os.CreateTemp(tmpdir, "")
   216  	if err != nil {
   217  		t.Fatalf("Couldn't create tmpfile: %v", err)
   218  	}
   219  	tests := []struct {
   220  		name     string
   221  		filename string
   222  		want     bool
   223  	}{
   224  		{
   225  			name:     "file exist",
   226  			filename: tmpfile.Name(),
   227  			want:     true,
   228  		},
   229  		{
   230  			name:     "file does not exist",
   231  			filename: "foo",
   232  			want:     false,
   233  		},
   234  		{
   235  			name:     "file path is a dir",
   236  			filename: tmpdir,
   237  			want:     false,
   238  		},
   239  	}
   240  	for _, tt := range tests {
   241  		t.Run(tt.name, func(t *testing.T) {
   242  			if got, _ := fileExists(tt.filename); got != tt.want {
   243  				t.Errorf("fileExists() = %v, want %v", got, tt.want)
   244  			}
   245  		})
   246  	}
   247  }
   248  
   249  func TestPKICertificateReadWriterExists(t *testing.T) {
   250  	tmpdir, err := os.MkdirTemp("", "")
   251  	if err != nil {
   252  		t.Fatalf("Couldn't create tmpdir: %v", err)
   253  	}
   254  	defer func() {
   255  		err = os.RemoveAll(tmpdir)
   256  		if err != nil {
   257  			t.Fatalf("Fail to remove tmpdir: %v", err)
   258  		}
   259  	}()
   260  	filename := "testfile"
   261  	tmpfilepath := filepath.Join(tmpdir, fmt.Sprintf(filename+".crt"))
   262  	err = os.WriteFile(tmpfilepath, nil, 0644)
   263  	if err != nil {
   264  		t.Fatalf("Couldn't write file: %v", err)
   265  	}
   266  	type fields struct {
   267  		baseName       string
   268  		certificateDir string
   269  	}
   270  	tests := []struct {
   271  		name   string
   272  		fields fields
   273  		want   bool
   274  	}{
   275  		{
   276  			name: "cert file exists",
   277  			fields: fields{
   278  				baseName:       filename,
   279  				certificateDir: tmpdir,
   280  			},
   281  			want: true,
   282  		},
   283  		{
   284  			name: "cert file does not exist",
   285  			fields: fields{
   286  				baseName:       "foo",
   287  				certificateDir: tmpdir,
   288  			},
   289  			want: false,
   290  		},
   291  	}
   292  	for _, tt := range tests {
   293  		t.Run(tt.name, func(t *testing.T) {
   294  			rw := &pkiCertificateReadWriter{
   295  				baseName:       tt.fields.baseName,
   296  				certificateDir: tt.fields.certificateDir,
   297  			}
   298  			if got, _ := rw.Exists(); got != tt.want {
   299  				t.Errorf("pkiCertificateReadWriter.Exists() = %v, want %v", got, tt.want)
   300  			}
   301  		})
   302  	}
   303  }
   304  
   305  func TestKubeConfigReadWriterExists(t *testing.T) {
   306  	tmpdir, err := os.MkdirTemp("", "")
   307  	if err != nil {
   308  		t.Fatalf("Couldn't create tmpdir: %v", err)
   309  	}
   310  	defer func() {
   311  		err = os.RemoveAll(tmpdir)
   312  		if err != nil {
   313  			t.Fatalf("Fail to remove tmpdir: %v", err)
   314  		}
   315  	}()
   316  	tmpfile, err := os.CreateTemp(tmpdir, "")
   317  	if err != nil {
   318  		t.Fatalf("Couldn't create tmpfile: %v", err)
   319  	}
   320  	tests := []struct {
   321  		name               string
   322  		kubeConfigFilePath string
   323  		want               bool
   324  	}{
   325  		{
   326  			name:               "file exists",
   327  			kubeConfigFilePath: tmpfile.Name(),
   328  			want:               true,
   329  		},
   330  		{
   331  			name:               "file does not exist",
   332  			kubeConfigFilePath: "foo",
   333  			want:               false,
   334  		},
   335  	}
   336  	for _, tt := range tests {
   337  		t.Run(tt.name, func(t *testing.T) {
   338  			rw := &kubeConfigReadWriter{
   339  				kubeConfigFilePath: tt.kubeConfigFilePath,
   340  			}
   341  			if got, _ := rw.Exists(); got != tt.want {
   342  				t.Errorf("kubeConfigReadWriter.Exists() = %v, want %v", got, tt.want)
   343  			}
   344  		})
   345  	}
   346  }
   347  

View as plain text