From 75a80d5aba4d3034df6113bdb6a80cea75f480c6 Mon Sep 17 00:00:00 2001 From: SataQiu Date: Sat, 19 Aug 2023 11:33:29 +0800 Subject: [PATCH] kubeadm: add validation to verify that the CertificateKey is a valid hex encoded AES key --- .../app/apis/kubeadm/validation/validation.go | 24 +++++++++++-- .../kubeadm/validation/validation_test.go | 36 +++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go index e1bf34f22d1..8ca8c79b509 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go +++ b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go @@ -17,6 +17,7 @@ limitations under the License. package validation import ( + "encoding/hex" "fmt" "net" "net/url" @@ -54,7 +55,7 @@ func ValidateInitConfiguration(c *kubeadm.InitConfiguration) field.ErrorList { allErrs = append(allErrs, ValidateClusterConfiguration(&c.ClusterConfiguration)...) // TODO(Arvinderpal): update advertiseAddress validation for dual-stack once it's implemented. allErrs = append(allErrs, ValidateAPIEndpoint(&c.LocalAPIEndpoint, field.NewPath("localAPIEndpoint"))...) - // TODO: Maybe validate that .CertificateKey is a valid hex encoded AES key + allErrs = append(allErrs, ValidateCertificateKey(c.CertificateKey, field.NewPath("certificateKey"))...) return allErrs } @@ -98,7 +99,7 @@ func ValidateJoinControlPlane(c *kubeadm.JoinControlPlane, fldPath *field.Path) allErrs := field.ErrorList{} if c != nil { allErrs = append(allErrs, ValidateAPIEndpoint(&c.LocalAPIEndpoint, fldPath.Child("localAPIEndpoint"))...) - // TODO: Maybe validate that .CertificateKey is a valid hex encoded AES key + allErrs = append(allErrs, ValidateCertificateKey(c.CertificateKey, field.NewPath("certificateKey"))...) } return allErrs } @@ -594,6 +595,25 @@ func ValidateAPIEndpoint(c *kubeadm.APIEndpoint, fldPath *field.Path) field.Erro return allErrs } +// ValidateCertificateKey validates the certificate key is a valid hex encoded AES key +func ValidateCertificateKey(certificateKey string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if len(certificateKey) > 0 { + decodedKey, err := hex.DecodeString(certificateKey) + if err != nil { + return append(allErrs, field.Invalid(fldPath, certificateKey, fmt.Sprintf("certificate key decoding error: %v", err))) + } + + k := len(decodedKey) + if k != constants.CertificateKeySize { + allErrs = append(allErrs, field.Invalid(fldPath, certificateKey, fmt.Sprintf("invalid certificate key size %d, the key must be an AES key of size %d", k, constants.CertificateKeySize))) + } + } + + return allErrs +} + // ValidateIgnorePreflightErrors validates duplicates in: // - ignore-preflight-errors flag and // - ignorePreflightErrors field in {Init,Join}Configuration files. diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go b/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go index c98fcdbef12..e41f867c9dd 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go +++ b/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go @@ -455,6 +455,42 @@ func TestValidateAPIEndpoint(t *testing.T) { } } +func TestValidateCertificateKey(t *testing.T) { + var tests = []struct { + name string + certificateKey string + expected bool + }{ + { + name: "Valid certificate key", + certificateKey: "e6a2eb8581237ab72a4f494f30285ec12a9694d750b9785706a83bfcbbbd2204", + expected: true, + }, + { + name: "Invalid hex encoded string", + certificateKey: "z6a2eb8581237ab72a4f494f30285ec12a9694d750b9785706a83bfcbbbd2204", + expected: false, + }, + { + name: "Invalid AES key size", + certificateKey: "e6a2", + expected: false, + }, + } + for _, rt := range tests { + actual := ValidateCertificateKey(rt.certificateKey, nil) + t.Log(actual) + if (len(actual) == 0) != rt.expected { + t.Errorf( + "%s test case failed:\n\texpected: %t\n\t actual: %t", + rt.name, + rt.expected, + (len(actual) == 0), + ) + } + } +} + // TODO: Create a separated test for ValidateClusterConfiguration func TestValidateInitConfiguration(t *testing.T) { nodename := "valid-nodename"