Skip to content

Commit 13885bf

Browse files
authored
Merge pull request kubernetes#77252 from rojkov/rewrite-CreateServiceAccountKeyAndPublicKeyFiles
kubeadm: do unit testing of actual public function
2 parents b07f311 + a6d7920 commit 13885bf

File tree

3 files changed

+60
-109
lines changed

3 files changed

+60
-109
lines changed

cmd/kubeadm/app/phases/certs/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ go_library(
3939
"//cmd/kubeadm/app/constants:go_default_library",
4040
"//cmd/kubeadm/app/util/pkiutil:go_default_library",
4141
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
42+
"//staging/src/k8s.io/client-go/util/keyutil:go_default_library",
4243
"//vendor/github.com/pkg/errors:go_default_library",
4344
"//vendor/k8s.io/klog:go_default_library",
4445
],

cmd/kubeadm/app/phases/certs/certs.go

Lines changed: 19 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525

2626
"github.com/pkg/errors"
2727
certutil "k8s.io/client-go/util/cert"
28+
"k8s.io/client-go/util/keyutil"
2829
"k8s.io/klog"
2930
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
3031
pkiutil "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
@@ -67,27 +68,31 @@ func CreatePKIAssets(cfg *kubeadmapi.InitConfiguration) error {
6768
// If the sa public/private key files already exists in the target folder, they are used only if evaluated equals; otherwise an error is returned.
6869
func CreateServiceAccountKeyAndPublicKeyFiles(certsDir string) error {
6970
klog.V(1).Infoln("creating a new public/private key files for signing service account users")
70-
saSigningKey, err := NewServiceAccountSigningKey()
71+
_, err := keyutil.PrivateKeyFromFile(filepath.Join(certsDir, kubeadmconstants.ServiceAccountPrivateKeyName))
72+
if err == nil {
73+
// kubeadm doesn't validate the existing certificate key more than this;
74+
// Basically, if we find a key file with the same path kubeadm thinks those files
75+
// are equal and doesn't bother writing a new file
76+
fmt.Printf("[certs] Using the existing %q key\n", kubeadmconstants.ServiceAccountKeyBaseName)
77+
return nil
78+
} else if !os.IsNotExist(err) {
79+
return errors.Wrapf(err, "file %s existed but it could not be loaded properly", kubeadmconstants.ServiceAccountPrivateKeyName)
80+
}
81+
82+
// The key does NOT exist, let's generate it now
83+
key, err := pkiutil.NewPrivateKey()
7184
if err != nil {
7285
return err
7386
}
7487

75-
return writeKeyFilesIfNotExist(
76-
certsDir,
77-
kubeadmconstants.ServiceAccountKeyBaseName,
78-
saSigningKey,
79-
)
80-
}
88+
// Write .key and .pub files to disk
89+
fmt.Printf("[certs] Generating %q key and public key\n", kubeadmconstants.ServiceAccountKeyBaseName)
8190

82-
// NewServiceAccountSigningKey generate public/private key pairs for signing service account tokens.
83-
func NewServiceAccountSigningKey() (crypto.Signer, error) {
84-
// The key does NOT exist, let's generate it now
85-
saSigningKey, err := pkiutil.NewPrivateKey()
86-
if err != nil {
87-
return nil, errors.Wrap(err, "failure while creating service account token signing key")
91+
if err := pkiutil.WriteKey(certsDir, kubeadmconstants.ServiceAccountKeyBaseName, key); err != nil {
92+
return err
8893
}
8994

90-
return saSigningKey, nil
95+
return pkiutil.WritePublicKey(certsDir, kubeadmconstants.ServiceAccountKeyBaseName, key.Public())
9196
}
9297

9398
// CreateCACertAndKeyFiles generates and writes out a given certificate authority.
@@ -246,42 +251,6 @@ func writeCertificateFilesIfNotExist(pkiDir string, baseName string, signingCert
246251
return nil
247252
}
248253

249-
// writeKeyFilesIfNotExist write a new key to the given path.
250-
// If there already is a key file at the given path; kubeadm tries to load it and check if the values in the
251-
// existing and the expected key equals. If they do; kubeadm will just skip writing the file as it's up-to-date,
252-
// otherwise this function returns an error.
253-
func writeKeyFilesIfNotExist(pkiDir string, baseName string, key crypto.Signer) error {
254-
255-
// Checks if the key exists in the PKI directory
256-
if pkiutil.CertOrKeyExist(pkiDir, baseName) {
257-
258-
// Try to load .key from the PKI directory
259-
_, err := pkiutil.TryLoadKeyFromDisk(pkiDir, baseName)
260-
if err != nil {
261-
return errors.Wrapf(err, "%s key existed but it could not be loaded properly", baseName)
262-
}
263-
264-
// kubeadm doesn't validate the existing certificate key more than this;
265-
// Basically, if we find a key file with the same path kubeadm thinks those files
266-
// are equal and doesn't bother writing a new file
267-
fmt.Printf("[certs] Using the existing %q key\n", baseName)
268-
} else {
269-
270-
// Write .key and .pub files to disk
271-
fmt.Printf("[certs] Generating %q key and public key\n", baseName)
272-
273-
if err := pkiutil.WriteKey(pkiDir, baseName, key); err != nil {
274-
return errors.Wrapf(err, "failure while saving %s key", baseName)
275-
}
276-
277-
if err := pkiutil.WritePublicKey(pkiDir, baseName, key.Public()); err != nil {
278-
return errors.Wrapf(err, "failure while saving %s public key", baseName)
279-
}
280-
}
281-
282-
return nil
283-
}
284-
285254
// writeCSRFilesIfNotExist writes a new CSR to the given path.
286255
// If there already is a CSR file at the given path; kubeadm tries to load it and check if it's a valid certificate.
287256
// otherwise this function returns an error.

cmd/kubeadm/app/phases/certs/certs_test.go

Lines changed: 40 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -301,84 +301,65 @@ func TestWriteCSRFilesIfNotExist(t *testing.T) {
301301

302302
}
303303

304-
func TestWriteKeyFilesIfNotExist(t *testing.T) {
305-
306-
setupKey, _ := NewServiceAccountSigningKey()
307-
key, _ := NewServiceAccountSigningKey()
304+
func TestCreateServiceAccountKeyAndPublicKeyFiles(t *testing.T) {
305+
setupKey, err := keyutil.MakeEllipticPrivateKeyPEM()
306+
if err != nil {
307+
t.Fatalf("Can't setup test: %v", err)
308+
}
308309

309-
var tests = []struct {
310-
setupFunc func(pkiDir string) error
311-
expectedError bool
312-
expectedKey crypto.Signer
310+
tcases := []struct {
311+
name string
312+
setupFunc func(pkiDir string) error
313+
expectedErr bool
314+
expectedKey []byte
313315
}{
314316
{ // key does not exists > key written
315-
expectedKey: key,
317+
name: "generate successfully",
316318
},
317319
{ // key exists > existing key used
320+
name: "use existing key",
318321
setupFunc: func(pkiDir string) error {
319-
return writeKeyFilesIfNotExist(pkiDir, "dummy", setupKey)
322+
err := keyutil.WriteKey(filepath.Join(pkiDir, kubeadmconstants.ServiceAccountPrivateKeyName), setupKey)
323+
return err
320324
},
321325
expectedKey: setupKey,
322326
},
323327
{ // some file exists, but it is not a valid key > err
328+
name: "empty key",
324329
setupFunc: func(pkiDir string) error {
325-
testutil.SetupEmptyFiles(t, pkiDir, "dummy.key")
330+
testutil.SetupEmptyFiles(t, pkiDir, kubeadmconstants.ServiceAccountPrivateKeyName)
326331
return nil
327332
},
328-
expectedError: true,
333+
expectedErr: true,
329334
},
330335
}
336+
for _, tt := range tcases {
337+
t.Run(tt.name, func(t *testing.T) {
338+
dir := testutil.SetupTempDir(t)
339+
defer os.RemoveAll(dir)
331340

332-
for _, test := range tests {
333-
// Create temp folder for the test case
334-
tmpdir := testutil.SetupTempDir(t)
335-
defer os.RemoveAll(tmpdir)
336-
337-
// executes setup func (if necessary)
338-
if test.setupFunc != nil {
339-
if err := test.setupFunc(tmpdir); err != nil {
340-
t.Errorf("error executing setupFunc: %v", err)
341-
continue
341+
if tt.setupFunc != nil {
342+
if err := tt.setupFunc(dir); err != nil {
343+
t.Fatalf("error executing setupFunc: %v", err)
344+
}
342345
}
343-
}
344346

345-
// executes create func
346-
err := writeKeyFilesIfNotExist(tmpdir, "dummy", key)
347-
348-
if !test.expectedError && err != nil {
349-
t.Errorf("error writeKeyFilesIfNotExist failed when not expected to fail: %v", err)
350-
continue
351-
} else if test.expectedError && err == nil {
352-
t.Error("error writeKeyFilesIfNotExist didn't failed when expected")
353-
continue
354-
} else if test.expectedError || test.expectedKey == nil {
355-
continue
356-
}
357-
358-
// asserts expected files are there
359-
testutil.AssertFileExists(t, tmpdir, "dummy.key", "dummy.pub")
360-
361-
// check created key
362-
resultingKey, err := pkiutil.TryLoadKeyFromDisk(tmpdir, "dummy")
363-
if err != nil {
364-
t.Errorf("failure reading created key: %v", err)
365-
continue
366-
}
367-
368-
resultingKeyPEM, err := keyutil.MarshalPrivateKeyToPEM(resultingKey)
369-
if err != nil {
370-
t.Errorf("failure marshaling created key: %v", err)
371-
continue
372-
}
373-
374-
expectedKeyPEM, err := keyutil.MarshalPrivateKeyToPEM(test.expectedKey)
375-
if err != nil {
376-
t.Fatalf("Failed to marshal expected private key: %v", err)
377-
}
347+
err := CreateServiceAccountKeyAndPublicKeyFiles(dir)
348+
if (err != nil) != tt.expectedErr {
349+
t.Fatalf("expected error: %v, got: %v, error: %v", tt.expectedErr, err != nil, err)
350+
} else if tt.expectedErr {
351+
return
352+
}
378353

379-
if !bytes.Equal(resultingKeyPEM, expectedKeyPEM) {
380-
t.Error("created key does not match expected key")
381-
}
354+
resultingKeyPEM, wasGenerated, err := keyutil.LoadOrGenerateKeyFile(filepath.Join(dir, kubeadmconstants.ServiceAccountPrivateKeyName))
355+
if err != nil {
356+
t.Errorf("Can't load created key: %v", err)
357+
} else if wasGenerated {
358+
t.Error("The key was not created")
359+
} else if tt.expectedKey != nil && !bytes.Equal(resultingKeyPEM, tt.expectedKey) {
360+
t.Error("Non-existing key is used")
361+
}
362+
})
382363
}
383364
}
384365

0 commit comments

Comments
 (0)