...

Source file src/k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil/pki_helpers_test.go

Documentation: k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil

     1  /*
     2  Copyright 2016 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 pkiutil
    18  
    19  import (
    20  	"crypto"
    21  	"crypto/ecdsa"
    22  	"crypto/elliptic"
    23  	"crypto/rand"
    24  	"crypto/x509"
    25  	"fmt"
    26  	"net"
    27  	"os"
    28  	"path/filepath"
    29  	"reflect"
    30  	"testing"
    31  
    32  	certutil "k8s.io/client-go/util/cert"
    33  	netutils "k8s.io/utils/net"
    34  
    35  	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
    36  )
    37  
    38  var (
    39  	// TestMain generates the bellow certs and keys so that
    40  	// they are reused in tests whenever possible
    41  
    42  	rootCACert, servCert *x509.Certificate
    43  	rootCAKey, servKey   crypto.Signer
    44  
    45  	ecdsaKey *ecdsa.PrivateKey
    46  )
    47  
    48  func TestMain(m *testing.M) {
    49  	var err error
    50  
    51  	rootCACert, rootCAKey, err = NewCertificateAuthority(&CertConfig{
    52  		Config: certutil.Config{
    53  			CommonName: "Root CA 1",
    54  		},
    55  		EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmRSA2048,
    56  	})
    57  	if err != nil {
    58  		panic(fmt.Sprintf("Failed generating Root CA: %v", err))
    59  	}
    60  	if !rootCACert.IsCA {
    61  		panic("rootCACert is not a valid CA")
    62  	}
    63  
    64  	servCert, servKey, err = NewCertAndKey(rootCACert, rootCAKey, &CertConfig{
    65  		Config: certutil.Config{
    66  			CommonName: "kubernetes",
    67  			Usages:     []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
    68  		},
    69  	})
    70  	if err != nil {
    71  		panic(fmt.Sprintf("Failed generating serving cert/key: %v", err))
    72  	}
    73  
    74  	ecdsaKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    75  	if err != nil {
    76  		panic("Could not generate ECDSA key")
    77  	}
    78  
    79  	os.Exit(m.Run())
    80  }
    81  
    82  func TestNewCertAndKey(t *testing.T) {
    83  	var tests = []struct {
    84  		name string
    85  		key  crypto.Signer
    86  	}{
    87  		{
    88  			name: "ECDSA should succeed",
    89  			key:  ecdsaKey,
    90  		},
    91  	}
    92  
    93  	for _, rt := range tests {
    94  		t.Run(rt.name, func(t *testing.T) {
    95  			caCert := &x509.Certificate{}
    96  			config := &CertConfig{
    97  				Config: certutil.Config{
    98  					CommonName:   "test",
    99  					Organization: []string{"test"},
   100  					Usages:       []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
   101  				},
   102  			}
   103  			_, _, err := NewCertAndKey(caCert, rt.key, config)
   104  			if err != nil {
   105  				t.Errorf("failed NewCertAndKey: %v", err)
   106  			}
   107  		})
   108  	}
   109  }
   110  
   111  func TestHasServerAuth(t *testing.T) {
   112  	// Override NewPrivateKey to reuse the same key for all certs
   113  	// since this test is only checking cert.ExtKeyUsage
   114  	privateKeyFunc := NewPrivateKey
   115  	NewPrivateKey = func(kubeadmapi.EncryptionAlgorithmType) (crypto.Signer, error) {
   116  		return rootCAKey, nil
   117  	}
   118  	defer func() {
   119  		NewPrivateKey = privateKeyFunc
   120  	}()
   121  
   122  	var tests = []struct {
   123  		name     string
   124  		config   CertConfig
   125  		expected bool
   126  	}{
   127  		{
   128  			name: "has ServerAuth",
   129  			config: CertConfig{
   130  				Config: certutil.Config{
   131  					CommonName: "test",
   132  					Usages:     []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   133  				},
   134  			},
   135  			expected: true,
   136  		},
   137  		{
   138  			name: "has ServerAuth ECDSA",
   139  			config: CertConfig{
   140  				Config: certutil.Config{
   141  					CommonName: "test",
   142  					Usages:     []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   143  				},
   144  				EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmECDSAP256,
   145  			},
   146  			expected: true,
   147  		},
   148  		{
   149  			name: "doesn't have ServerAuth",
   150  			config: CertConfig{
   151  				Config: certutil.Config{
   152  					CommonName: "test",
   153  					Usages:     []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
   154  				},
   155  			},
   156  			expected: false,
   157  		},
   158  	}
   159  
   160  	for _, rt := range tests {
   161  		t.Run(rt.name, func(t *testing.T) {
   162  			cert, _, err := NewCertAndKey(rootCACert, rootCAKey, &rt.config)
   163  			if err != nil {
   164  				t.Fatalf("Couldn't create cert: %v", err)
   165  			}
   166  			actual := HasServerAuth(cert)
   167  			if actual != rt.expected {
   168  				t.Errorf(
   169  					"failed HasServerAuth:\n\texpected: %t\n\t  actual: %t",
   170  					rt.expected,
   171  					actual,
   172  				)
   173  			}
   174  		})
   175  	}
   176  }
   177  
   178  func TestWriteCertAndKey(t *testing.T) {
   179  	tmpdir, err := os.MkdirTemp("", "")
   180  	if err != nil {
   181  		t.Fatalf("Couldn't create tmpdir")
   182  	}
   183  	defer os.RemoveAll(tmpdir)
   184  
   185  	caCert := &x509.Certificate{}
   186  	actual := WriteCertAndKey(tmpdir, "foo", caCert, rootCAKey)
   187  	if actual != nil {
   188  		t.Errorf(
   189  			"failed WriteCertAndKey with an error: %v",
   190  			actual,
   191  		)
   192  	}
   193  }
   194  
   195  func TestWriteCert(t *testing.T) {
   196  	tmpdir, err := os.MkdirTemp("", "")
   197  	if err != nil {
   198  		t.Fatalf("Couldn't create tmpdir")
   199  	}
   200  	defer os.RemoveAll(tmpdir)
   201  
   202  	caCert := &x509.Certificate{}
   203  	actual := WriteCert(tmpdir, "foo", caCert)
   204  	if actual != nil {
   205  		t.Errorf(
   206  			"failed WriteCert with an error: %v",
   207  			actual,
   208  		)
   209  	}
   210  }
   211  
   212  func TestWriteCertBundle(t *testing.T) {
   213  	tmpdir, err := os.MkdirTemp("", "")
   214  	if err != nil {
   215  		t.Fatalf("Couldn't create tmpdir")
   216  	}
   217  	defer os.RemoveAll(tmpdir)
   218  
   219  	certs := []*x509.Certificate{{}, {}}
   220  
   221  	actual := WriteCertBundle(tmpdir, "foo", certs)
   222  	if actual != nil {
   223  		t.Errorf("failed WriteCertBundle with an error: %v", actual)
   224  	}
   225  }
   226  
   227  func TestWriteKey(t *testing.T) {
   228  	tmpdir, err := os.MkdirTemp("", "")
   229  	if err != nil {
   230  		t.Fatalf("Couldn't create tmpdir")
   231  	}
   232  	defer os.RemoveAll(tmpdir)
   233  
   234  	actual := WriteKey(tmpdir, "foo", rootCAKey)
   235  	if actual != nil {
   236  		t.Errorf(
   237  			"failed WriteCertAndKey with an error: %v",
   238  			actual,
   239  		)
   240  	}
   241  }
   242  
   243  func TestWritePublicKey(t *testing.T) {
   244  	tmpdir, err := os.MkdirTemp("", "")
   245  	if err != nil {
   246  		t.Fatalf("Couldn't create tmpdir")
   247  	}
   248  	defer os.RemoveAll(tmpdir)
   249  
   250  	actual := WritePublicKey(tmpdir, "foo", rootCAKey.Public())
   251  	if actual != nil {
   252  		t.Errorf(
   253  			"failed WriteCertAndKey with an error: %v",
   254  			actual,
   255  		)
   256  	}
   257  }
   258  
   259  func TestCertOrKeyExist(t *testing.T) {
   260  	tmpdir, err := os.MkdirTemp("", "")
   261  	if err != nil {
   262  		t.Fatalf("Couldn't create tmpdir")
   263  	}
   264  	defer os.RemoveAll(tmpdir)
   265  
   266  	if err = WriteCertAndKey(tmpdir, "foo-0", rootCACert, rootCAKey); err != nil {
   267  		t.Errorf(
   268  			"failed WriteCertAndKey with an error: %v",
   269  			err,
   270  		)
   271  	}
   272  	if err = WriteCert(tmpdir, "foo-1", rootCACert); err != nil {
   273  		t.Errorf(
   274  			"failed WriteCert with an error: %v",
   275  			err,
   276  		)
   277  	}
   278  
   279  	var tests = []struct {
   280  		desc     string
   281  		path     string
   282  		name     string
   283  		expected bool
   284  	}{
   285  		{
   286  			desc:     "empty path and name",
   287  			path:     "",
   288  			name:     "",
   289  			expected: false,
   290  		},
   291  		{
   292  			desc:     "valid path and name, both cert and key exist",
   293  			path:     tmpdir,
   294  			name:     "foo-0",
   295  			expected: true,
   296  		},
   297  		{
   298  			desc:     "valid path and name, only cert exist",
   299  			path:     tmpdir,
   300  			name:     "foo-1",
   301  			expected: true,
   302  		},
   303  	}
   304  	for _, rt := range tests {
   305  		t.Run(rt.name, func(t *testing.T) {
   306  			actual := CertOrKeyExist(rt.path, rt.name)
   307  			if actual != rt.expected {
   308  				t.Errorf(
   309  					"failed CertOrKeyExist:\n\texpected: %t\n\t  actual: %t",
   310  					rt.expected,
   311  					actual,
   312  				)
   313  			}
   314  		})
   315  	}
   316  }
   317  
   318  func TestTryLoadCertAndKeyFromDisk(t *testing.T) {
   319  	tmpdir, err := os.MkdirTemp("", "")
   320  	if err != nil {
   321  		t.Fatalf("Couldn't create tmpdir")
   322  	}
   323  	defer os.RemoveAll(tmpdir)
   324  
   325  	err = WriteCertAndKey(tmpdir, "foo", rootCACert, rootCAKey)
   326  	if err != nil {
   327  		t.Fatalf(
   328  			"failed to write cert and key with an error: %v",
   329  			err,
   330  		)
   331  	}
   332  
   333  	var tests = []struct {
   334  		desc     string
   335  		path     string
   336  		name     string
   337  		expected bool
   338  	}{
   339  		{
   340  			desc:     "empty path and name",
   341  			path:     "",
   342  			name:     "",
   343  			expected: false,
   344  		},
   345  		{
   346  			desc:     "valid path and name",
   347  			path:     tmpdir,
   348  			name:     "foo",
   349  			expected: true,
   350  		},
   351  	}
   352  	for _, rt := range tests {
   353  		t.Run(rt.desc, func(t *testing.T) {
   354  			_, _, actual := TryLoadCertAndKeyFromDisk(rt.path, rt.name)
   355  			if (actual == nil) != rt.expected {
   356  				t.Errorf(
   357  					"failed TryLoadCertAndKeyFromDisk:\n\texpected: %t\n\t  actual: %t",
   358  					rt.expected,
   359  					(actual == nil),
   360  				)
   361  			}
   362  		})
   363  	}
   364  }
   365  
   366  func TestTryLoadCertFromDisk(t *testing.T) {
   367  	tmpdir, err := os.MkdirTemp("", "")
   368  	if err != nil {
   369  		t.Fatalf("Couldn't create tmpdir")
   370  	}
   371  	defer os.RemoveAll(tmpdir)
   372  
   373  	err = WriteCert(tmpdir, "foo", rootCACert)
   374  	if err != nil {
   375  		t.Fatalf(
   376  			"failed to write cert and key with an error: %v",
   377  			err,
   378  		)
   379  	}
   380  
   381  	var tests = []struct {
   382  		desc     string
   383  		path     string
   384  		name     string
   385  		expected bool
   386  	}{
   387  		{
   388  			desc:     "empty path and name",
   389  			path:     "",
   390  			name:     "",
   391  			expected: false,
   392  		},
   393  		{
   394  			desc:     "valid path and name",
   395  			path:     tmpdir,
   396  			name:     "foo",
   397  			expected: true,
   398  		},
   399  	}
   400  	for _, rt := range tests {
   401  		t.Run(rt.desc, func(t *testing.T) {
   402  			_, actual := TryLoadCertFromDisk(rt.path, rt.name)
   403  			if (actual == nil) != rt.expected {
   404  				t.Errorf(
   405  					"failed TryLoadCertAndKeyFromDisk:\n\texpected: %t\n\t  actual: %t",
   406  					rt.expected,
   407  					(actual == nil),
   408  				)
   409  			}
   410  		})
   411  	}
   412  }
   413  
   414  func TestTryLoadCertChainFromDisk(t *testing.T) {
   415  	tmpdir, err := os.MkdirTemp("", "")
   416  	if err != nil {
   417  		t.Fatalf("Couldn't create tmpdir")
   418  	}
   419  	defer os.RemoveAll(tmpdir)
   420  
   421  	err = WriteCert(tmpdir, "leaf", servCert)
   422  	if err != nil {
   423  		t.Fatalf("failed to write cert: %v", err)
   424  	}
   425  
   426  	// rootCACert is treated as an intermediate CA here
   427  	bundle := []*x509.Certificate{servCert, rootCACert}
   428  	err = WriteCertBundle(tmpdir, "bundle", bundle)
   429  	if err != nil {
   430  		t.Fatalf("failed to write cert bundle: %v", err)
   431  	}
   432  
   433  	var tests = []struct {
   434  		desc          string
   435  		path          string
   436  		name          string
   437  		expected      bool
   438  		intermediates int
   439  	}{
   440  		{
   441  			desc:          "empty path and name",
   442  			path:          "",
   443  			name:          "",
   444  			expected:      false,
   445  			intermediates: 0,
   446  		},
   447  		{
   448  			desc:          "leaf certificate",
   449  			path:          tmpdir,
   450  			name:          "leaf",
   451  			expected:      true,
   452  			intermediates: 0,
   453  		},
   454  		{
   455  			desc:          "certificate bundle",
   456  			path:          tmpdir,
   457  			name:          "bundle",
   458  			expected:      true,
   459  			intermediates: 1,
   460  		},
   461  	}
   462  	for _, rt := range tests {
   463  		t.Run(rt.desc, func(t *testing.T) {
   464  			_, intermediates, actual := TryLoadCertChainFromDisk(rt.path, rt.name)
   465  			if (actual == nil) != rt.expected {
   466  				t.Errorf(
   467  					"failed TryLoadCertChainFromDisk:\n\texpected: %t\n\t  actual: %t",
   468  					rt.expected,
   469  					(actual == nil),
   470  				)
   471  			}
   472  			if len(intermediates) != rt.intermediates {
   473  				t.Errorf(
   474  					"TryLoadCertChainFromDisk returned the wrong number of intermediate certificates:\n\texpected: %d\n\t  actual: %d",
   475  					rt.intermediates,
   476  					len(intermediates),
   477  				)
   478  			}
   479  		})
   480  	}
   481  }
   482  
   483  func TestTryLoadKeyFromDisk(t *testing.T) {
   484  	var tests = []struct {
   485  		desc       string
   486  		pathSuffix string
   487  		name       string
   488  		caKey      crypto.Signer
   489  		expected   bool
   490  	}{
   491  		{
   492  			desc:       "empty path and name",
   493  			pathSuffix: "somegarbage",
   494  			name:       "",
   495  			caKey:      rootCAKey,
   496  			expected:   false,
   497  		},
   498  		{
   499  			desc:       "RSA valid path and name",
   500  			pathSuffix: "",
   501  			name:       "foo",
   502  			caKey:      rootCAKey,
   503  			expected:   true,
   504  		},
   505  		{
   506  			desc:       "ECDSA valid path and name",
   507  			pathSuffix: "",
   508  			name:       "foo",
   509  			caKey:      ecdsaKey,
   510  			expected:   true,
   511  		},
   512  	}
   513  	for _, rt := range tests {
   514  		t.Run(rt.desc, func(t *testing.T) {
   515  			tmpdir, err := os.MkdirTemp("", "")
   516  			if err != nil {
   517  				t.Fatalf("Couldn't create tmpdir")
   518  			}
   519  			defer os.RemoveAll(tmpdir)
   520  
   521  			err = WriteKey(tmpdir, "foo", rt.caKey)
   522  			if err != nil {
   523  				t.Errorf(
   524  					"failed to write key with an error: %v",
   525  					err,
   526  				)
   527  			}
   528  			_, actual := TryLoadKeyFromDisk(tmpdir+rt.pathSuffix, rt.name)
   529  			if (actual == nil) != rt.expected {
   530  				t.Errorf(
   531  					"failed TryLoadCertAndKeyFromDisk:\n\texpected: %t\n\t  actual: %t",
   532  					rt.expected,
   533  					(actual == nil),
   534  				)
   535  			}
   536  		})
   537  	}
   538  }
   539  
   540  func TestPathsForCertAndKey(t *testing.T) {
   541  	crtPath, keyPath := PathsForCertAndKey("/foo", "bar")
   542  	expectedPath := filepath.FromSlash("/foo/bar.crt")
   543  	if crtPath != expectedPath {
   544  		t.Errorf("unexpected certificate path: %s", crtPath)
   545  	}
   546  	expectedPath = filepath.FromSlash("/foo/bar.key")
   547  	if keyPath != expectedPath {
   548  		t.Errorf("unexpected key path: %s", keyPath)
   549  	}
   550  }
   551  
   552  func TestPathForCert(t *testing.T) {
   553  	crtPath := pathForCert("/foo", "bar")
   554  	expectedPath := filepath.FromSlash("/foo/bar.crt")
   555  	if crtPath != expectedPath {
   556  		t.Errorf("unexpected certificate path: %s", crtPath)
   557  	}
   558  }
   559  
   560  func TestPathForKey(t *testing.T) {
   561  	keyPath := pathForKey("/foo", "bar")
   562  	expectedPath := filepath.FromSlash("/foo/bar.key")
   563  	if keyPath != expectedPath {
   564  		t.Errorf("unexpected certificate path: %s", keyPath)
   565  	}
   566  }
   567  
   568  func TestPathForPublicKey(t *testing.T) {
   569  	pubPath := pathForPublicKey("/foo", "bar")
   570  	expectedPath := filepath.FromSlash("/foo/bar.pub")
   571  	if pubPath != expectedPath {
   572  		t.Errorf("unexpected certificate path: %s", pubPath)
   573  	}
   574  }
   575  
   576  func TestPathForCSR(t *testing.T) {
   577  	csrPath := pathForCSR("/foo", "bar")
   578  	expectedPath := filepath.FromSlash("/foo/bar.csr")
   579  	if csrPath != expectedPath {
   580  		t.Errorf("unexpected certificate path: %s", csrPath)
   581  	}
   582  }
   583  
   584  func TestGetAPIServerAltNames(t *testing.T) {
   585  
   586  	var tests = []struct {
   587  		desc                string
   588  		name                string
   589  		cfg                 *kubeadmapi.InitConfiguration
   590  		expectedDNSNames    []string
   591  		expectedIPAddresses []string
   592  	}{
   593  		{
   594  			desc: "empty name",
   595  			name: "",
   596  			cfg: &kubeadmapi.InitConfiguration{
   597  				LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4"},
   598  				ClusterConfiguration: kubeadmapi.ClusterConfiguration{
   599  					ControlPlaneEndpoint: "api.k8s.io:6443",
   600  					Networking:           kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
   601  					APIServer: kubeadmapi.APIServer{
   602  						CertSANs: []string{"10.1.245.94", "10.1.245.95", "1.2.3.L", "invalid,commas,in,DNS"},
   603  					},
   604  				},
   605  				NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-hostname"},
   606  			},
   607  			expectedDNSNames:    []string{"valid-hostname", "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster.local", "api.k8s.io"},
   608  			expectedIPAddresses: []string{"10.96.0.1", "1.2.3.4", "10.1.245.94", "10.1.245.95"},
   609  		},
   610  		{
   611  			desc: "ControlPlaneEndpoint IP",
   612  			name: "ControlPlaneEndpoint IP",
   613  			cfg: &kubeadmapi.InitConfiguration{
   614  				LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4"},
   615  				ClusterConfiguration: kubeadmapi.ClusterConfiguration{
   616  					ControlPlaneEndpoint: "4.5.6.7:6443",
   617  					Networking:           kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
   618  					APIServer: kubeadmapi.APIServer{
   619  						CertSANs: []string{"10.1.245.94", "10.1.245.95", "1.2.3.L", "invalid,commas,in,DNS"},
   620  					},
   621  				},
   622  				NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-hostname"},
   623  			},
   624  			expectedDNSNames:    []string{"valid-hostname", "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster.local"},
   625  			expectedIPAddresses: []string{"10.96.0.1", "1.2.3.4", "10.1.245.94", "10.1.245.95", "4.5.6.7"},
   626  		},
   627  	}
   628  
   629  	for _, rt := range tests {
   630  		t.Run(rt.desc, func(t *testing.T) {
   631  			altNames, err := GetAPIServerAltNames(rt.cfg)
   632  			if err != nil {
   633  				t.Fatalf("failed calling GetAPIServerAltNames: %s: %v", rt.name, err)
   634  			}
   635  
   636  			for _, DNSName := range rt.expectedDNSNames {
   637  				found := false
   638  				for _, val := range altNames.DNSNames {
   639  					if val == DNSName {
   640  						found = true
   641  						break
   642  					}
   643  				}
   644  
   645  				if !found {
   646  					t.Errorf("%s: altNames does not contain DNSName %s but %v", rt.name, DNSName, altNames.DNSNames)
   647  				}
   648  			}
   649  
   650  			for _, IPAddress := range rt.expectedIPAddresses {
   651  				found := false
   652  				for _, val := range altNames.IPs {
   653  					if val.Equal(netutils.ParseIPSloppy(IPAddress)) {
   654  						found = true
   655  						break
   656  					}
   657  				}
   658  
   659  				if !found {
   660  					t.Errorf("%s: altNames does not contain IPAddress %s but %v", rt.name, IPAddress, altNames.IPs)
   661  				}
   662  			}
   663  		})
   664  	}
   665  }
   666  
   667  func TestGetEtcdAltNames(t *testing.T) {
   668  	proxy := "user-etcd-proxy"
   669  	proxyIP := "10.10.10.100"
   670  	cfg := &kubeadmapi.InitConfiguration{
   671  		LocalAPIEndpoint: kubeadmapi.APIEndpoint{
   672  			AdvertiseAddress: "1.2.3.4",
   673  		},
   674  		NodeRegistration: kubeadmapi.NodeRegistrationOptions{
   675  			Name: "myNode",
   676  		},
   677  		ClusterConfiguration: kubeadmapi.ClusterConfiguration{
   678  			Etcd: kubeadmapi.Etcd{
   679  				Local: &kubeadmapi.LocalEtcd{
   680  					ServerCertSANs: []string{
   681  						proxy,
   682  						proxyIP,
   683  						"1.2.3.L",
   684  						"invalid,commas,in,DNS",
   685  					},
   686  				},
   687  			},
   688  		},
   689  	}
   690  
   691  	altNames, err := GetEtcdAltNames(cfg)
   692  	if err != nil {
   693  		t.Fatalf("failed calling GetEtcdAltNames: %v", err)
   694  	}
   695  
   696  	expectedDNSNames := []string{"myNode", "localhost", proxy}
   697  	for _, DNSName := range expectedDNSNames {
   698  		t.Run(DNSName, func(t *testing.T) {
   699  			found := false
   700  			for _, val := range altNames.DNSNames {
   701  				if val == DNSName {
   702  					found = true
   703  					break
   704  				}
   705  			}
   706  
   707  			if !found {
   708  				t.Errorf("altNames does not contain DNSName %s", DNSName)
   709  			}
   710  		})
   711  	}
   712  
   713  	expectedIPAddresses := []string{"1.2.3.4", "127.0.0.1", net.IPv6loopback.String(), proxyIP}
   714  	for _, IPAddress := range expectedIPAddresses {
   715  		t.Run(IPAddress, func(t *testing.T) {
   716  			found := false
   717  			for _, val := range altNames.IPs {
   718  				if val.Equal(netutils.ParseIPSloppy(IPAddress)) {
   719  					found = true
   720  					break
   721  				}
   722  			}
   723  
   724  			if !found {
   725  				t.Errorf("altNames does not contain IPAddress %s", IPAddress)
   726  			}
   727  		})
   728  	}
   729  }
   730  
   731  func TestGetEtcdPeerAltNames(t *testing.T) {
   732  	hostname := "valid-hostname"
   733  	proxy := "user-etcd-proxy"
   734  	proxyIP := "10.10.10.100"
   735  	advertiseIP := "1.2.3.4"
   736  	cfg := &kubeadmapi.InitConfiguration{
   737  		LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: advertiseIP},
   738  		ClusterConfiguration: kubeadmapi.ClusterConfiguration{
   739  			Etcd: kubeadmapi.Etcd{
   740  				Local: &kubeadmapi.LocalEtcd{
   741  					PeerCertSANs: []string{
   742  						proxy,
   743  						proxyIP,
   744  						"1.2.3.L",
   745  						"invalid,commas,in,DNS",
   746  					},
   747  				},
   748  			},
   749  		},
   750  		NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: hostname},
   751  	}
   752  
   753  	altNames, err := GetEtcdPeerAltNames(cfg)
   754  	if err != nil {
   755  		t.Fatalf("failed calling GetEtcdPeerAltNames: %v", err)
   756  	}
   757  
   758  	expectedDNSNames := []string{hostname, proxy}
   759  	for _, DNSName := range expectedDNSNames {
   760  		t.Run(DNSName, func(t *testing.T) {
   761  			found := false
   762  			for _, val := range altNames.DNSNames {
   763  				if val == DNSName {
   764  					found = true
   765  					break
   766  				}
   767  			}
   768  
   769  			if !found {
   770  				t.Errorf("altNames does not contain DNSName %s", DNSName)
   771  			}
   772  
   773  			expectedIPAddresses := []string{advertiseIP, proxyIP}
   774  			for _, IPAddress := range expectedIPAddresses {
   775  				found := false
   776  				for _, val := range altNames.IPs {
   777  					if val.Equal(netutils.ParseIPSloppy(IPAddress)) {
   778  						found = true
   779  						break
   780  					}
   781  				}
   782  
   783  				if !found {
   784  					t.Errorf("altNames does not contain IPAddress %s", IPAddress)
   785  				}
   786  			}
   787  		})
   788  	}
   789  }
   790  
   791  func TestAppendSANsToAltNames(t *testing.T) {
   792  	var tests = []struct {
   793  		sans     []string
   794  		expected int
   795  	}{
   796  		{[]string{}, 0},
   797  		{[]string{"abc"}, 1},
   798  		{[]string{"*.abc"}, 1},
   799  		{[]string{"**.abc"}, 0},
   800  		{[]string{"a.*.bc"}, 0},
   801  		{[]string{"a.*.bc", "abc.def"}, 1},
   802  		{[]string{"a*.bc", "abc.def"}, 1},
   803  	}
   804  	for _, rt := range tests {
   805  		altNames := certutil.AltNames{}
   806  		appendSANsToAltNames(&altNames, rt.sans, "foo")
   807  		actual := len(altNames.DNSNames)
   808  		if actual != rt.expected {
   809  			t.Errorf(
   810  				"failed AppendSANsToAltNames Numbers:\n\texpected: %d\n\t  actual: %d",
   811  				rt.expected,
   812  				actual,
   813  			)
   814  		}
   815  	}
   816  
   817  }
   818  
   819  func TestRemoveDuplicateAltNames(t *testing.T) {
   820  	tests := []struct {
   821  		args *certutil.AltNames
   822  		want *certutil.AltNames
   823  	}{
   824  		{
   825  			&certutil.AltNames{},
   826  			&certutil.AltNames{},
   827  		},
   828  		{
   829  			&certutil.AltNames{
   830  				DNSNames: []string{"a", "a"},
   831  				IPs:      []net.IP{{127, 0, 0, 1}},
   832  			},
   833  			&certutil.AltNames{
   834  				DNSNames: []string{"a"},
   835  				IPs:      []net.IP{{127, 0, 0, 1}},
   836  			},
   837  		},
   838  		{
   839  			&certutil.AltNames{
   840  				DNSNames: []string{"a"},
   841  				IPs:      []net.IP{{127, 0, 0, 1}, {127, 0, 0, 1}},
   842  			},
   843  			&certutil.AltNames{
   844  				DNSNames: []string{"a"},
   845  				IPs:      []net.IP{{127, 0, 0, 1}},
   846  			},
   847  		},
   848  		{
   849  			&certutil.AltNames{
   850  				DNSNames: []string{"a", "a"},
   851  				IPs:      []net.IP{{127, 0, 0, 1}, {127, 0, 0, 1}},
   852  			},
   853  			&certutil.AltNames{
   854  				DNSNames: []string{"a"},
   855  				IPs:      []net.IP{{127, 0, 0, 1}},
   856  			},
   857  		},
   858  	}
   859  	for _, tt := range tests {
   860  		RemoveDuplicateAltNames(tt.args)
   861  		if !reflect.DeepEqual(tt.args, tt.want) {
   862  			t.Errorf("Wanted %v, got %v", tt.want, tt.args)
   863  		}
   864  	}
   865  }
   866  
   867  func TestVerifyCertChain(t *testing.T) {
   868  	tmpdir, err := os.MkdirTemp("", "")
   869  	if err != nil {
   870  		t.Fatalf("Couldn't create tmpdir")
   871  	}
   872  	defer os.RemoveAll(tmpdir)
   873  
   874  	rootCert2, rootKey2, err := NewCertificateAuthority(&CertConfig{
   875  		Config: certutil.Config{CommonName: "Root CA 2"},
   876  	})
   877  	if err != nil {
   878  		t.Errorf("failed to create root CA cert and key with an error: %v", err)
   879  	}
   880  
   881  	intCert2, intKey2, err := NewIntermediateCertificateAuthority(rootCert2, rootKey2, &CertConfig{
   882  		Config: certutil.Config{
   883  			CommonName: "Intermediate CA 2",
   884  			Usages:     []x509.ExtKeyUsage{},
   885  		},
   886  	})
   887  	if err != nil {
   888  		t.Errorf("failed to create intermediate CA cert and key with an error: %v", err)
   889  	}
   890  
   891  	leafCert2, _, err := NewCertAndKey(intCert2, intKey2, &CertConfig{
   892  		Config: certutil.Config{
   893  			CommonName: "Leaf Certificate 2",
   894  			Usages:     []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   895  		},
   896  	})
   897  	if err != nil {
   898  		t.Errorf("failed to create leaf cert and key with an error: %v", err)
   899  	}
   900  
   901  	var tests = []struct {
   902  		desc          string
   903  		leaf          *x509.Certificate
   904  		intermediates []*x509.Certificate
   905  		root          *x509.Certificate
   906  		expected      bool
   907  	}{
   908  		{
   909  			desc:          "without any intermediate CAs",
   910  			leaf:          servCert,
   911  			intermediates: []*x509.Certificate{},
   912  			root:          rootCACert,
   913  			expected:      true,
   914  		},
   915  		{
   916  			desc:          "missing intermediate CA",
   917  			leaf:          leafCert2,
   918  			intermediates: []*x509.Certificate{},
   919  			root:          rootCert2,
   920  			expected:      false,
   921  		},
   922  		{
   923  			desc:          "with one intermediate CA",
   924  			leaf:          leafCert2,
   925  			intermediates: []*x509.Certificate{intCert2},
   926  			root:          rootCert2,
   927  			expected:      true,
   928  		},
   929  	}
   930  	for _, rt := range tests {
   931  		t.Run(rt.desc, func(t *testing.T) {
   932  			actual := VerifyCertChain(rt.leaf, rt.intermediates, rt.root)
   933  			if (actual == nil) != rt.expected {
   934  				t.Errorf(
   935  					"failed VerifyCertChain:\n\texpected: %t\n\t  actual: %t",
   936  					rt.expected,
   937  					(actual == nil),
   938  				)
   939  			}
   940  		})
   941  	}
   942  }
   943  
   944  func TestRSAKeySizeFromAlgorithmType(t *testing.T) {
   945  	var tests = []struct {
   946  		algorithm    kubeadmapi.EncryptionAlgorithmType
   947  		expectedSize int
   948  	}{
   949  		{algorithm: "unknown", expectedSize: 0},
   950  		{algorithm: "", expectedSize: 2048},
   951  		{algorithm: kubeadmapi.EncryptionAlgorithmRSA2048, expectedSize: 2048},
   952  		{algorithm: kubeadmapi.EncryptionAlgorithmRSA3072, expectedSize: 3072},
   953  		{algorithm: kubeadmapi.EncryptionAlgorithmRSA4096, expectedSize: 4096},
   954  	}
   955  	for _, rt := range tests {
   956  		t.Run(string(rt.algorithm), func(t *testing.T) {
   957  			size := rsaKeySizeFromAlgorithmType(rt.algorithm)
   958  			if size != rt.expectedSize {
   959  				t.Errorf("expected size: %d, got: %d", rt.expectedSize, size)
   960  			}
   961  		})
   962  	}
   963  }
   964  

View as plain text