Merge pull request #120064 from SataQiu/feat-kubeadm-20230819
kubeadm: add validation to verify that the CertificateKey is a valid hex encoded AES key
This commit is contained in:
		@@ -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.
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user