mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-11-03 23:40:03 +00:00 
			
		
		
		
	The selected key type is defined by kubeadm's --feature-gates option: if it contains PublicKeysECDSA=true then ECDSA keys will be generated and used. By default RSA keys are used still. Signed-off-by: Dmitry Rozhkov <dmitry.rozhkov@linux.intel.com>
		
			
				
	
	
		
			819 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			819 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2016 The Kubernetes Authors.
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
*/
 | 
						|
 | 
						|
package certs
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"crypto"
 | 
						|
	"crypto/sha256"
 | 
						|
	"crypto/x509"
 | 
						|
	"io/ioutil"
 | 
						|
	"net"
 | 
						|
	"os"
 | 
						|
	"path"
 | 
						|
	"path/filepath"
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"github.com/pkg/errors"
 | 
						|
	"github.com/stretchr/testify/assert"
 | 
						|
 | 
						|
	certutil "k8s.io/client-go/util/cert"
 | 
						|
	"k8s.io/client-go/util/keyutil"
 | 
						|
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
						|
	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
						|
	certstestutil "k8s.io/kubernetes/cmd/kubeadm/app/util/certs"
 | 
						|
	"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
 | 
						|
	testutil "k8s.io/kubernetes/cmd/kubeadm/test"
 | 
						|
)
 | 
						|
 | 
						|
func createTestCSR(t *testing.T) (*x509.CertificateRequest, crypto.Signer) {
 | 
						|
	csr, key, err := pkiutil.NewCSRAndKey(
 | 
						|
		&pkiutil.CertConfig{
 | 
						|
			Config: certutil.Config{
 | 
						|
				CommonName: "testCert",
 | 
						|
			},
 | 
						|
		})
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("couldn't create test cert: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	return csr, key
 | 
						|
}
 | 
						|
 | 
						|
func TestWriteCertificateAuthorityFilesIfNotExist(t *testing.T) {
 | 
						|
	setupCert, setupKey := certstestutil.CreateCACert(t)
 | 
						|
	caCert, caKey := certstestutil.CreateCACert(t)
 | 
						|
 | 
						|
	var tests = []struct {
 | 
						|
		setupFunc     func(pkiDir string) error
 | 
						|
		expectedError bool
 | 
						|
		expectedCa    *x509.Certificate
 | 
						|
	}{
 | 
						|
		{ // ca cert does not exists > ca written
 | 
						|
			expectedCa: caCert,
 | 
						|
		},
 | 
						|
		{ // ca cert exists, is ca > existing ca used
 | 
						|
			setupFunc: func(pkiDir string) error {
 | 
						|
				return writeCertificateAuthorityFilesIfNotExist(pkiDir, "dummy", setupCert, setupKey)
 | 
						|
			},
 | 
						|
			expectedCa: setupCert,
 | 
						|
		},
 | 
						|
		{ // some file exists, but it is not a valid ca cert > err
 | 
						|
			setupFunc: func(pkiDir string) error {
 | 
						|
				testutil.SetupEmptyFiles(t, pkiDir, "dummy.crt")
 | 
						|
				return nil
 | 
						|
			},
 | 
						|
			expectedError: true,
 | 
						|
		},
 | 
						|
		{ // cert exists, but it is not a ca > err
 | 
						|
			setupFunc: func(pkiDir string) error {
 | 
						|
				cert, key, config := certstestutil.CreateTestCert(t, setupCert, setupKey, certutil.AltNames{})
 | 
						|
				return writeCertificateFilesIfNotExist(pkiDir, "dummy", setupCert, cert, key, config)
 | 
						|
			},
 | 
						|
			expectedError: true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, test := range tests {
 | 
						|
		// Create temp folder for the test case
 | 
						|
		tmpdir := testutil.SetupTempDir(t)
 | 
						|
		defer os.RemoveAll(tmpdir)
 | 
						|
 | 
						|
		// executes setup func (if necessary)
 | 
						|
		if test.setupFunc != nil {
 | 
						|
			if err := test.setupFunc(tmpdir); err != nil {
 | 
						|
				t.Errorf("error executing setupFunc: %v", err)
 | 
						|
				continue
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// executes create func
 | 
						|
		err := writeCertificateAuthorityFilesIfNotExist(tmpdir, "dummy", caCert, caKey)
 | 
						|
 | 
						|
		if !test.expectedError && err != nil {
 | 
						|
			t.Errorf("error writeCertificateAuthorityFilesIfNotExist failed when not expected to fail: %v", err)
 | 
						|
			continue
 | 
						|
		} else if test.expectedError && err == nil {
 | 
						|
			t.Error("error writeCertificateAuthorityFilesIfNotExist didn't failed when expected")
 | 
						|
			continue
 | 
						|
		} else if test.expectedError {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		// asserts expected files are there
 | 
						|
		testutil.AssertFileExists(t, tmpdir, "dummy.key", "dummy.crt")
 | 
						|
 | 
						|
		// check created cert
 | 
						|
		resultingCaCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(tmpdir, "dummy")
 | 
						|
		if err != nil {
 | 
						|
			t.Errorf("failure reading created cert: %v", err)
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if !resultingCaCert.Equal(test.expectedCa) {
 | 
						|
			t.Error("created ca cert does not match expected ca cert")
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestWriteCertificateFilesIfNotExist(t *testing.T) {
 | 
						|
	altNames := certutil.AltNames{
 | 
						|
		DNSNames: []string{"example.com"},
 | 
						|
		IPs: []net.IP{
 | 
						|
			net.IPv4(0, 0, 0, 0),
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	caCert, caKey := certstestutil.CreateCACert(t)
 | 
						|
	setupCert, setupKey, _ := certstestutil.CreateTestCert(t, caCert, caKey, altNames)
 | 
						|
	cert, key, config := certstestutil.CreateTestCert(t, caCert, caKey, altNames)
 | 
						|
 | 
						|
	var tests = []struct {
 | 
						|
		setupFunc     func(pkiDir string) error
 | 
						|
		expectedError bool
 | 
						|
		expectedCert  *x509.Certificate
 | 
						|
	}{
 | 
						|
		{ // cert does not exists > cert written
 | 
						|
			expectedCert: cert,
 | 
						|
		},
 | 
						|
		{ // cert exists, is signed by the same ca, missing SANs (dns name) > err
 | 
						|
			setupFunc: func(pkiDir string) error {
 | 
						|
				setupCert, setupKey, setupConfig := certstestutil.CreateTestCert(t, caCert, caKey, certutil.AltNames{
 | 
						|
					IPs: []net.IP{
 | 
						|
						net.IPv4(0, 0, 0, 0),
 | 
						|
					},
 | 
						|
				})
 | 
						|
				return writeCertificateFilesIfNotExist(pkiDir, "dummy", caCert, setupCert, setupKey, setupConfig)
 | 
						|
			},
 | 
						|
			expectedError: true,
 | 
						|
		},
 | 
						|
		{ // cert exists, is signed by the same ca, missing SANs (IP address) > err
 | 
						|
			setupFunc: func(pkiDir string) error {
 | 
						|
				setupCert, setupKey, setupConfig := certstestutil.CreateTestCert(t, caCert, caKey, certutil.AltNames{
 | 
						|
					DNSNames: []string{"example.com"},
 | 
						|
				})
 | 
						|
				return writeCertificateFilesIfNotExist(pkiDir, "dummy", caCert, setupCert, setupKey, setupConfig)
 | 
						|
			},
 | 
						|
			expectedError: true,
 | 
						|
		},
 | 
						|
		{ // cert exists, is signed by the same ca, all SANs present > existing cert used
 | 
						|
			setupFunc: func(pkiDir string) error {
 | 
						|
				return writeCertificateFilesIfNotExist(pkiDir, "dummy", caCert, setupCert, setupKey, config)
 | 
						|
			},
 | 
						|
			expectedCert: setupCert,
 | 
						|
		},
 | 
						|
		{ // some file exists, but it is not a valid cert > err
 | 
						|
			setupFunc: func(pkiDir string) error {
 | 
						|
				testutil.SetupEmptyFiles(t, pkiDir, "dummy.crt")
 | 
						|
				return nil
 | 
						|
			},
 | 
						|
			expectedError: true,
 | 
						|
		},
 | 
						|
		{ // cert exists, is signed by another ca > err
 | 
						|
			setupFunc: func(pkiDir string) error {
 | 
						|
				anotherCaCert, anotherCaKey := certstestutil.CreateCACert(t)
 | 
						|
				anotherCert, anotherKey, config := certstestutil.CreateTestCert(t, anotherCaCert, anotherCaKey, certutil.AltNames{})
 | 
						|
 | 
						|
				return writeCertificateFilesIfNotExist(pkiDir, "dummy", anotherCaCert, anotherCert, anotherKey, config)
 | 
						|
			},
 | 
						|
			expectedError: true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, test := range tests {
 | 
						|
		// Create temp folder for the test case
 | 
						|
		tmpdir := testutil.SetupTempDir(t)
 | 
						|
		defer os.RemoveAll(tmpdir)
 | 
						|
 | 
						|
		// executes setup func (if necessary)
 | 
						|
		if test.setupFunc != nil {
 | 
						|
			if err := test.setupFunc(tmpdir); err != nil {
 | 
						|
				t.Errorf("error executing setupFunc: %v", err)
 | 
						|
				continue
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// executes create func
 | 
						|
		err := writeCertificateFilesIfNotExist(tmpdir, "dummy", caCert, cert, key, config)
 | 
						|
 | 
						|
		if !test.expectedError && err != nil {
 | 
						|
			t.Errorf("error writeCertificateFilesIfNotExist failed when not expected to fail: %v", err)
 | 
						|
			continue
 | 
						|
		} else if test.expectedError && err == nil {
 | 
						|
			t.Error("error writeCertificateFilesIfNotExist didn't fail when expected")
 | 
						|
			continue
 | 
						|
		} else if test.expectedError {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		// asserts expected files are there
 | 
						|
		testutil.AssertFileExists(t, tmpdir, "dummy.key", "dummy.crt")
 | 
						|
 | 
						|
		// check created cert
 | 
						|
		resultingCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(tmpdir, "dummy")
 | 
						|
		if err != nil {
 | 
						|
			t.Errorf("failure reading created cert: %v", err)
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if !resultingCert.Equal(test.expectedCert) {
 | 
						|
			t.Error("created cert does not match expected cert")
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestWriteCSRFilesIfNotExist(t *testing.T) {
 | 
						|
	csr, key := createTestCSR(t)
 | 
						|
	csr2, key2 := createTestCSR(t)
 | 
						|
 | 
						|
	var tests = []struct {
 | 
						|
		name          string
 | 
						|
		setupFunc     func(csrPath string) error
 | 
						|
		expectedError bool
 | 
						|
		expectedCSR   *x509.CertificateRequest
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name:        "no files exist",
 | 
						|
			expectedCSR: csr,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "other key exists",
 | 
						|
			setupFunc: func(csrPath string) error {
 | 
						|
				if err := pkiutil.WriteCSR(csrPath, "dummy", csr2); err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
				return pkiutil.WriteKey(csrPath, "dummy", key2)
 | 
						|
			},
 | 
						|
			expectedCSR: csr2,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "existing CSR is garbage",
 | 
						|
			setupFunc: func(csrPath string) error {
 | 
						|
				return ioutil.WriteFile(path.Join(csrPath, "dummy.csr"), []byte("a--bunch--of-garbage"), os.ModePerm)
 | 
						|
			},
 | 
						|
			expectedError: true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, test := range tests {
 | 
						|
		t.Run(test.name, func(t *testing.T) {
 | 
						|
			tmpdir := testutil.SetupTempDir(t)
 | 
						|
			defer os.RemoveAll(tmpdir)
 | 
						|
 | 
						|
			if test.setupFunc != nil {
 | 
						|
				if err := test.setupFunc(tmpdir); err != nil {
 | 
						|
					t.Fatalf("couldn't set up test: %v", err)
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if err := writeCSRFilesIfNotExist(tmpdir, "dummy", csr, key); err != nil {
 | 
						|
				if test.expectedError {
 | 
						|
					return
 | 
						|
				}
 | 
						|
				t.Fatalf("unexpected error %v: ", err)
 | 
						|
			}
 | 
						|
 | 
						|
			if test.expectedError {
 | 
						|
				t.Fatal("Expected error, but got none")
 | 
						|
			}
 | 
						|
 | 
						|
			parsedCSR, _, err := pkiutil.TryLoadCSRAndKeyFromDisk(tmpdir, "dummy")
 | 
						|
			if err != nil {
 | 
						|
				t.Fatalf("couldn't load csr and key: %v", err)
 | 
						|
			}
 | 
						|
 | 
						|
			if sha256.Sum256(test.expectedCSR.Raw) != sha256.Sum256(parsedCSR.Raw) {
 | 
						|
				t.Error("expected csr's fingerprint does not match ")
 | 
						|
			}
 | 
						|
 | 
						|
		})
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
func TestCreateServiceAccountKeyAndPublicKeyFiles(t *testing.T) {
 | 
						|
	setupKey, err := keyutil.MakeEllipticPrivateKeyPEM()
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("Can't setup test: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	tcases := []struct {
 | 
						|
		name        string
 | 
						|
		setupFunc   func(pkiDir string) error
 | 
						|
		expectedErr bool
 | 
						|
		expectedKey []byte
 | 
						|
	}{
 | 
						|
		{ // key does not exists > key written
 | 
						|
			name: "generate successfully",
 | 
						|
		},
 | 
						|
		{ // key exists > existing key used
 | 
						|
			name: "use existing key",
 | 
						|
			setupFunc: func(pkiDir string) error {
 | 
						|
				err := keyutil.WriteKey(filepath.Join(pkiDir, kubeadmconstants.ServiceAccountPrivateKeyName), setupKey)
 | 
						|
				return err
 | 
						|
			},
 | 
						|
			expectedKey: setupKey,
 | 
						|
		},
 | 
						|
		{ // some file exists, but it is not a valid key > err
 | 
						|
			name: "empty key",
 | 
						|
			setupFunc: func(pkiDir string) error {
 | 
						|
				testutil.SetupEmptyFiles(t, pkiDir, kubeadmconstants.ServiceAccountPrivateKeyName)
 | 
						|
				return nil
 | 
						|
			},
 | 
						|
			expectedErr: true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, tt := range tcases {
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			dir := testutil.SetupTempDir(t)
 | 
						|
			defer os.RemoveAll(dir)
 | 
						|
 | 
						|
			if tt.setupFunc != nil {
 | 
						|
				if err := tt.setupFunc(dir); err != nil {
 | 
						|
					t.Fatalf("error executing setupFunc: %v", err)
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			err := CreateServiceAccountKeyAndPublicKeyFiles(dir, x509.RSA)
 | 
						|
			if (err != nil) != tt.expectedErr {
 | 
						|
				t.Fatalf("expected error: %v, got: %v, error: %v", tt.expectedErr, err != nil, err)
 | 
						|
			} else if tt.expectedErr {
 | 
						|
				return
 | 
						|
			}
 | 
						|
 | 
						|
			resultingKeyPEM, wasGenerated, err := keyutil.LoadOrGenerateKeyFile(filepath.Join(dir, kubeadmconstants.ServiceAccountPrivateKeyName))
 | 
						|
			if err != nil {
 | 
						|
				t.Errorf("Can't load created key: %v", err)
 | 
						|
			} else if wasGenerated {
 | 
						|
				t.Error("The key was not created")
 | 
						|
			} else if tt.expectedKey != nil && !bytes.Equal(resultingKeyPEM, tt.expectedKey) {
 | 
						|
				t.Error("Non-existing key is used")
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestSharedCertificateExists(t *testing.T) {
 | 
						|
	caCert, caKey := certstestutil.CreateCACert(t)
 | 
						|
	_, key, _ := certstestutil.CreateTestCert(t, caCert, caKey, certutil.AltNames{})
 | 
						|
	publicKey := key.Public()
 | 
						|
 | 
						|
	var tests = []struct {
 | 
						|
		name          string
 | 
						|
		files         certstestutil.PKIFiles
 | 
						|
		expectedError bool
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name: "success",
 | 
						|
			files: certstestutil.PKIFiles{
 | 
						|
				"ca.crt":             caCert,
 | 
						|
				"ca.key":             caKey,
 | 
						|
				"front-proxy-ca.crt": caCert,
 | 
						|
				"front-proxy-ca.key": caKey,
 | 
						|
				"sa.pub":             publicKey,
 | 
						|
				"sa.key":             key,
 | 
						|
				"etcd/ca.crt":        caCert,
 | 
						|
				"etcd/ca.key":        caKey,
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "missing ca.crt",
 | 
						|
			files: certstestutil.PKIFiles{
 | 
						|
				"ca.key":             caKey,
 | 
						|
				"front-proxy-ca.crt": caCert,
 | 
						|
				"front-proxy-ca.key": caKey,
 | 
						|
				"sa.pub":             publicKey,
 | 
						|
				"sa.key":             key,
 | 
						|
				"etcd/ca.crt":        caCert,
 | 
						|
				"etcd/ca.key":        caKey,
 | 
						|
			},
 | 
						|
			expectedError: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "missing sa.key",
 | 
						|
			files: certstestutil.PKIFiles{
 | 
						|
				"ca.crt":             caCert,
 | 
						|
				"ca.key":             caKey,
 | 
						|
				"front-proxy-ca.crt": caCert,
 | 
						|
				"front-proxy-ca.key": caKey,
 | 
						|
				"sa.pub":             publicKey,
 | 
						|
				"etcd/ca.crt":        caCert,
 | 
						|
				"etcd/ca.key":        caKey,
 | 
						|
			},
 | 
						|
			expectedError: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "missing front-proxy.crt",
 | 
						|
			files: certstestutil.PKIFiles{
 | 
						|
				"ca.crt":             caCert,
 | 
						|
				"ca.key":             caKey,
 | 
						|
				"front-proxy-ca.key": caKey,
 | 
						|
				"sa.pub":             publicKey,
 | 
						|
				"sa.key":             key,
 | 
						|
				"etcd/ca.crt":        caCert,
 | 
						|
				"etcd/ca.key":        caKey,
 | 
						|
			},
 | 
						|
			expectedError: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "missing etcd/ca.crt",
 | 
						|
			files: certstestutil.PKIFiles{
 | 
						|
				"ca.crt":             caCert,
 | 
						|
				"ca.key":             caKey,
 | 
						|
				"front-proxy-ca.key": caKey,
 | 
						|
				"sa.pub":             publicKey,
 | 
						|
				"sa.key":             key,
 | 
						|
				"etcd/ca.crt":        caCert,
 | 
						|
				"etcd/ca.key":        caKey,
 | 
						|
			},
 | 
						|
			expectedError: true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, test := range tests {
 | 
						|
		t.Run("", func(t *testing.T) {
 | 
						|
			tmpdir := testutil.SetupTempDir(t)
 | 
						|
			os.MkdirAll(tmpdir+"/etcd", os.ModePerm)
 | 
						|
			defer os.RemoveAll(tmpdir)
 | 
						|
 | 
						|
			cfg := &kubeadmapi.ClusterConfiguration{
 | 
						|
				CertificatesDir: tmpdir,
 | 
						|
			}
 | 
						|
 | 
						|
			// created expected keys
 | 
						|
			certstestutil.WritePKIFiles(t, tmpdir, test.files)
 | 
						|
 | 
						|
			// executes create func
 | 
						|
			ret, err := SharedCertificateExists(cfg)
 | 
						|
 | 
						|
			switch {
 | 
						|
			case !test.expectedError && err != nil:
 | 
						|
				t.Errorf("error SharedCertificateExists failed when not expected to fail: %v", err)
 | 
						|
			case test.expectedError && err == nil:
 | 
						|
				t.Errorf("error SharedCertificateExists didn't failed when expected")
 | 
						|
			case ret != (err == nil):
 | 
						|
				t.Errorf("error SharedCertificateExists returned %v when expected to return %v", ret, err == nil)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestCreatePKIAssetsWithSparseCerts(t *testing.T) {
 | 
						|
	for _, test := range certstestutil.GetSparseCertTestCases(t) {
 | 
						|
		t.Run(test.Name, func(t *testing.T) {
 | 
						|
			tmpdir := testutil.SetupTempDir(t)
 | 
						|
			defer os.RemoveAll(tmpdir)
 | 
						|
 | 
						|
			cfg := testutil.GetDefaultInternalConfig(t)
 | 
						|
			cfg.ClusterConfiguration.CertificatesDir = tmpdir
 | 
						|
 | 
						|
			certstestutil.WritePKIFiles(t, tmpdir, test.Files)
 | 
						|
 | 
						|
			err := CreatePKIAssets(cfg)
 | 
						|
			if err != nil {
 | 
						|
				if test.ExpectError {
 | 
						|
					return
 | 
						|
				}
 | 
						|
				t.Fatalf("Unexpected error: %v", err)
 | 
						|
			}
 | 
						|
			if test.ExpectError {
 | 
						|
				t.Fatal("Expected error from CreatePKIAssets, got none")
 | 
						|
			}
 | 
						|
			assertCertsExist(t, tmpdir)
 | 
						|
		})
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
func TestUsingExternalCA(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		name           string
 | 
						|
		setupFuncs     []func(cfg *kubeadmapi.InitConfiguration) error
 | 
						|
		externalCAFunc func(*kubeadmapi.ClusterConfiguration) (bool, error)
 | 
						|
		expected       bool
 | 
						|
		expectedErr    bool
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name: "Test External CA, when complete PKI exists",
 | 
						|
			setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{
 | 
						|
				CreatePKIAssets,
 | 
						|
			},
 | 
						|
			externalCAFunc: UsingExternalCA,
 | 
						|
			expected:       false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "Test External CA, when ca.key missing",
 | 
						|
			setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{
 | 
						|
				CreatePKIAssets,
 | 
						|
				deleteCertOrKey(kubeadmconstants.CAKeyName),
 | 
						|
			},
 | 
						|
			externalCAFunc: UsingExternalCA,
 | 
						|
			expected:       true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "Test External CA, when ca.key missing and signed certs are missing",
 | 
						|
			setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{
 | 
						|
				CreatePKIAssets,
 | 
						|
				deleteCertOrKey(kubeadmconstants.CAKeyName),
 | 
						|
				deleteCertOrKey(kubeadmconstants.APIServerCertName),
 | 
						|
			},
 | 
						|
			externalCAFunc: UsingExternalCA,
 | 
						|
			expected:       true,
 | 
						|
			expectedErr:    true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "Test External CA, when ca.key missing",
 | 
						|
			setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{
 | 
						|
				CreatePKIAssets,
 | 
						|
				deleteCertOrKey(kubeadmconstants.CAKeyName),
 | 
						|
			},
 | 
						|
			externalCAFunc: UsingExternalCA,
 | 
						|
			expected:       true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "Test External Front Proxy CA, when complete PKI exists",
 | 
						|
			setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{
 | 
						|
				CreatePKIAssets,
 | 
						|
			},
 | 
						|
			externalCAFunc: UsingExternalFrontProxyCA,
 | 
						|
			expected:       false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "Test External Front Proxy CA, when front-proxy-ca.key missing",
 | 
						|
			setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{
 | 
						|
				CreatePKIAssets,
 | 
						|
				deleteCertOrKey(kubeadmconstants.FrontProxyCAKeyName),
 | 
						|
			},
 | 
						|
			externalCAFunc: UsingExternalFrontProxyCA,
 | 
						|
			expected:       true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "Test External Front Proxy CA, when front-proxy-.key missing and signed certs are missing",
 | 
						|
			setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{
 | 
						|
				CreatePKIAssets,
 | 
						|
				deleteCertOrKey(kubeadmconstants.FrontProxyCAKeyName),
 | 
						|
				deleteCertOrKey(kubeadmconstants.FrontProxyClientCertName),
 | 
						|
			},
 | 
						|
			externalCAFunc: UsingExternalFrontProxyCA,
 | 
						|
			expected:       true,
 | 
						|
			expectedErr:    true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, test := range tests {
 | 
						|
		t.Run(test.name, func(t *testing.T) {
 | 
						|
			dir := testutil.SetupTempDir(t)
 | 
						|
			defer os.RemoveAll(dir)
 | 
						|
 | 
						|
			cfg := &kubeadmapi.InitConfiguration{
 | 
						|
				LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4"},
 | 
						|
				ClusterConfiguration: kubeadmapi.ClusterConfiguration{
 | 
						|
					Networking:      kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
 | 
						|
					CertificatesDir: dir,
 | 
						|
				},
 | 
						|
				NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-hostname"},
 | 
						|
			}
 | 
						|
 | 
						|
			for _, f := range test.setupFuncs {
 | 
						|
				if err := f(cfg); err != nil {
 | 
						|
					t.Errorf("error executing setup function: %v", err)
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			val, err := test.externalCAFunc(&cfg.ClusterConfiguration)
 | 
						|
			if val != test.expected {
 | 
						|
				t.Errorf("UsingExternalCA did not match expected: %v", test.expected)
 | 
						|
			}
 | 
						|
 | 
						|
			if (err != nil) != test.expectedErr {
 | 
						|
				t.Errorf("UsingExternalCA returned un expected err: %v", err)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestValidateMethods(t *testing.T) {
 | 
						|
 | 
						|
	caCert, caKey := certstestutil.CreateCACert(t)
 | 
						|
	cert, key, _ := certstestutil.CreateTestCert(t, caCert, caKey, certutil.AltNames{})
 | 
						|
 | 
						|
	tests := []struct {
 | 
						|
		name            string
 | 
						|
		files           certstestutil.PKIFiles
 | 
						|
		validateFunc    func(l certKeyLocation) error
 | 
						|
		loc             certKeyLocation
 | 
						|
		expectedSuccess bool
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name: "validateCACert",
 | 
						|
			files: certstestutil.PKIFiles{
 | 
						|
				"ca.crt": caCert,
 | 
						|
			},
 | 
						|
			validateFunc:    validateCACert,
 | 
						|
			loc:             certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"},
 | 
						|
			expectedSuccess: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "validateCACertAndKey (files present)",
 | 
						|
			files: certstestutil.PKIFiles{
 | 
						|
				"ca.crt": caCert,
 | 
						|
				"ca.key": caKey,
 | 
						|
			},
 | 
						|
			validateFunc:    validateCACertAndKey,
 | 
						|
			loc:             certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"},
 | 
						|
			expectedSuccess: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			files: certstestutil.PKIFiles{
 | 
						|
				"ca.crt": caCert,
 | 
						|
			},
 | 
						|
			name:            "validateCACertAndKey (key missing)",
 | 
						|
			validateFunc:    validateCACertAndKey,
 | 
						|
			loc:             certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"},
 | 
						|
			expectedSuccess: false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "validateSignedCert",
 | 
						|
			files: certstestutil.PKIFiles{
 | 
						|
				"ca.crt":        caCert,
 | 
						|
				"ca.key":        caKey,
 | 
						|
				"apiserver.crt": cert,
 | 
						|
				"apiserver.key": key,
 | 
						|
			},
 | 
						|
			validateFunc:    validateSignedCert,
 | 
						|
			loc:             certKeyLocation{caBaseName: "ca", baseName: "apiserver", uxName: "apiserver"},
 | 
						|
			expectedSuccess: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "validatePrivatePublicKey",
 | 
						|
			files: certstestutil.PKIFiles{
 | 
						|
				"sa.pub": key.Public(),
 | 
						|
				"sa.key": key,
 | 
						|
			},
 | 
						|
			validateFunc:    validatePrivatePublicKey,
 | 
						|
			loc:             certKeyLocation{baseName: "sa", uxName: "service account"},
 | 
						|
			expectedSuccess: true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, test := range tests {
 | 
						|
		dir := testutil.SetupTempDir(t)
 | 
						|
		defer os.RemoveAll(dir)
 | 
						|
		test.loc.pkiDir = dir
 | 
						|
 | 
						|
		certstestutil.WritePKIFiles(t, dir, test.files)
 | 
						|
 | 
						|
		err := test.validateFunc(test.loc)
 | 
						|
		if test.expectedSuccess && err != nil {
 | 
						|
			t.Errorf("expected success, error executing validateFunc: %v, %v", test.name, err)
 | 
						|
		} else if !test.expectedSuccess && err == nil {
 | 
						|
			t.Errorf("expected failure, no error executing validateFunc: %v", test.name)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestNewCSR(t *testing.T) {
 | 
						|
	kubeadmCert := KubeadmCertAPIServer
 | 
						|
	cfg := testutil.GetDefaultInternalConfig(t)
 | 
						|
 | 
						|
	certConfig, err := kubeadmCert.GetConfig(cfg)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("couldn't get cert config: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	csr, _, err := NewCSR(&kubeadmCert, cfg)
 | 
						|
 | 
						|
	if err != nil {
 | 
						|
		t.Errorf("invalid signature on CSR: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	assert.ElementsMatch(t, certConfig.Organization, csr.Subject.Organization, "organizations not equal")
 | 
						|
 | 
						|
	if csr.Subject.CommonName != certConfig.CommonName {
 | 
						|
		t.Errorf("expected common name %q, got %q", certConfig.CommonName, csr.Subject.CommonName)
 | 
						|
	}
 | 
						|
 | 
						|
	assert.ElementsMatch(t, certConfig.AltNames.DNSNames, csr.DNSNames, "dns names not equal")
 | 
						|
 | 
						|
	assert.Len(t, csr.IPAddresses, len(certConfig.AltNames.IPs))
 | 
						|
 | 
						|
	for i, ip := range csr.IPAddresses {
 | 
						|
		if !ip.Equal(certConfig.AltNames.IPs[i]) {
 | 
						|
			t.Errorf("[%d]: %v != %v", i, ip, certConfig.AltNames.IPs[i])
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestCreateCertificateFilesMethods(t *testing.T) {
 | 
						|
 | 
						|
	var tests = []struct {
 | 
						|
		createFunc    func(cfg *kubeadmapi.InitConfiguration) error
 | 
						|
		expectedFiles []string
 | 
						|
		externalEtcd  bool
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			createFunc: CreatePKIAssets,
 | 
						|
			expectedFiles: []string{
 | 
						|
				kubeadmconstants.CACertName, kubeadmconstants.CAKeyName,
 | 
						|
				kubeadmconstants.APIServerCertName, kubeadmconstants.APIServerKeyName,
 | 
						|
				kubeadmconstants.APIServerKubeletClientCertName, kubeadmconstants.APIServerKubeletClientKeyName,
 | 
						|
				kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdCAKeyName,
 | 
						|
				kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName,
 | 
						|
				kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName,
 | 
						|
				kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName,
 | 
						|
				kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName,
 | 
						|
				kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName,
 | 
						|
				kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName,
 | 
						|
				kubeadmconstants.FrontProxyClientCertName, kubeadmconstants.FrontProxyClientKeyName,
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			createFunc:   CreatePKIAssets,
 | 
						|
			externalEtcd: true,
 | 
						|
			expectedFiles: []string{
 | 
						|
				kubeadmconstants.CACertName, kubeadmconstants.CAKeyName,
 | 
						|
				kubeadmconstants.APIServerCertName, kubeadmconstants.APIServerKeyName,
 | 
						|
				kubeadmconstants.APIServerKubeletClientCertName, kubeadmconstants.APIServerKubeletClientKeyName,
 | 
						|
				kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName,
 | 
						|
				kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName,
 | 
						|
				kubeadmconstants.FrontProxyClientCertName, kubeadmconstants.FrontProxyClientKeyName,
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, test := range tests {
 | 
						|
		// Create temp folder for the test case
 | 
						|
		tmpdir := testutil.SetupTempDir(t)
 | 
						|
		defer os.RemoveAll(tmpdir)
 | 
						|
 | 
						|
		cfg := &kubeadmapi.InitConfiguration{
 | 
						|
			LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4"},
 | 
						|
			ClusterConfiguration: kubeadmapi.ClusterConfiguration{
 | 
						|
				Etcd:            kubeadmapi.Etcd{Local: &kubeadmapi.LocalEtcd{}},
 | 
						|
				Networking:      kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
 | 
						|
				CertificatesDir: tmpdir,
 | 
						|
			},
 | 
						|
			NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-hostname"},
 | 
						|
		}
 | 
						|
 | 
						|
		if test.externalEtcd {
 | 
						|
			if cfg.Etcd.External == nil {
 | 
						|
				cfg.Etcd.External = &kubeadmapi.ExternalEtcd{}
 | 
						|
			}
 | 
						|
			cfg.Etcd.Local = nil
 | 
						|
			cfg.Etcd.External.Endpoints = []string{"192.168.1.1:2379"}
 | 
						|
		}
 | 
						|
 | 
						|
		// executes create func
 | 
						|
		if err := test.createFunc(cfg); err != nil {
 | 
						|
			t.Errorf("error executing createFunc: %v", err)
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		// asserts expected files are there
 | 
						|
		testutil.AssertFileExists(t, tmpdir, test.expectedFiles...)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func deleteCertOrKey(name string) func(*kubeadmapi.InitConfiguration) error {
 | 
						|
	return func(cfg *kubeadmapi.InitConfiguration) error {
 | 
						|
		if err := os.Remove(filepath.Join(cfg.CertificatesDir, name)); err != nil {
 | 
						|
			return errors.Wrapf(err, "failed removing %s", name)
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func assertCertsExist(t *testing.T, dir string) {
 | 
						|
	tree, err := GetDefaultCertList().AsMap().CertTree()
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("unexpected error getting certificates: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	for caCert, certs := range tree {
 | 
						|
		if err := validateCACert(certKeyLocation{dir, caCert.BaseName, "", caCert.Name}); err != nil {
 | 
						|
			t.Errorf("couldn't validate CA certificate %v: %v", caCert.Name, err)
 | 
						|
			// Don't bother validating child certs, but do try the other CAs
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		for _, cert := range certs {
 | 
						|
			if err := validateSignedCert(certKeyLocation{dir, caCert.BaseName, cert.BaseName, cert.Name}); err != nil {
 | 
						|
				t.Errorf("couldn't validate certificate %v: %v", cert.Name, err)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |