mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 15:05:27 +00:00
kubeadm: enhance encryption algorithm support in v1beta4
Previous v1beta4 work added support for ClusterConfiguration.EncryptionAlgorithm, however the possible values were limited to just "RSA" (2048 key size) and "ECDSA" (P256). Allow more arbitrary algorithm types, that can also include key size or curve type encoded in the name: "RSA-2048" (default), "RSA-3072", "RSA-4096" or "ECDSA-P256". Update the deprecation notice of the PublicKeysECDSA FeatureGate as ideally it should be removed only after v1beta3 is removed.
This commit is contained in:
parent
a9e4f5b786
commit
2cab79710d
@ -94,7 +94,7 @@ func fuzzClusterConfiguration(obj *kubeadm.ClusterConfiguration, c fuzz.Continue
|
||||
obj.APIServer.ExtraEnvs = []kubeadm.EnvVar{}
|
||||
obj.Scheduler.ExtraEnvs = []kubeadm.EnvVar{}
|
||||
obj.Etcd.Local.ExtraEnvs = []kubeadm.EnvVar{}
|
||||
obj.EncryptionAlgorithm = kubeadm.EncryptionAlgorithmRSA
|
||||
obj.EncryptionAlgorithm = kubeadm.EncryptionAlgorithmRSA2048
|
||||
obj.Proxy.Disabled = false
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,7 @@ type ClusterConfiguration struct {
|
||||
ClusterName string
|
||||
|
||||
// EncryptionAlgorithm holds the type of asymmetric encryption algorithm used for keys and certificates.
|
||||
// Can be "RSA" (default algorithm, key size is 2048) or "ECDSA" (uses the P-256 elliptic curve).
|
||||
// Can be one of "RSA-2048" (default), "RSA-3072", "RSA-4096" or "ECDSA-P256".
|
||||
EncryptionAlgorithm EncryptionAlgorithmType
|
||||
}
|
||||
|
||||
@ -433,9 +433,9 @@ func (cfg *ClusterConfiguration) EncryptionAlgorithmType() EncryptionAlgorithmTy
|
||||
// TODO: remove this function when the feature gate is removed.
|
||||
if enabled, ok := cfg.FeatureGates[features.PublicKeysECDSA]; ok {
|
||||
if enabled {
|
||||
return EncryptionAlgorithmECDSA
|
||||
return EncryptionAlgorithmECDSAP256
|
||||
}
|
||||
return EncryptionAlgorithmRSA
|
||||
return EncryptionAlgorithmRSA2048
|
||||
}
|
||||
return cfg.EncryptionAlgorithm
|
||||
}
|
||||
@ -570,10 +570,14 @@ type EnvVar struct {
|
||||
type EncryptionAlgorithmType string
|
||||
|
||||
const (
|
||||
// EncryptionAlgorithmECDSA defines the ECDSA encryption algorithm type.
|
||||
EncryptionAlgorithmECDSA EncryptionAlgorithmType = "ECDSA"
|
||||
// EncryptionAlgorithmRSA defines the RSA encryption algorithm type.
|
||||
EncryptionAlgorithmRSA EncryptionAlgorithmType = "RSA"
|
||||
// EncryptionAlgorithmECDSAP256 defines the ECDSA encryption algorithm type with curve P256.
|
||||
EncryptionAlgorithmECDSAP256 EncryptionAlgorithmType = "ECDSA-P256"
|
||||
// EncryptionAlgorithmRSA2048 defines the RSA encryption algorithm type with key size 2048 bits.
|
||||
EncryptionAlgorithmRSA2048 EncryptionAlgorithmType = "RSA-2048"
|
||||
// EncryptionAlgorithmRSA3072 defines the RSA encryption algorithm type with key size 3072 bits.
|
||||
EncryptionAlgorithmRSA3072 EncryptionAlgorithmType = "RSA-3072"
|
||||
// EncryptionAlgorithmRSA4096 defines the RSA encryption algorithm type with key size 4096 bits.
|
||||
EncryptionAlgorithmRSA4096 EncryptionAlgorithmType = "RSA-4096"
|
||||
)
|
||||
|
||||
// Timeouts holds various timeouts that apply to kubeadm commands.
|
||||
|
@ -66,7 +66,7 @@ func Convert_kubeadm_ClusterConfiguration_To_v1beta3_ClusterConfiguration(in *ku
|
||||
func Convert_v1beta3_ClusterConfiguration_To_kubeadm_ClusterConfiguration(in *ClusterConfiguration, out *kubeadm.ClusterConfiguration, s conversion.Scope) error {
|
||||
// Required to pass validation and fuzzer tests. The field is missing in v1beta3, thus we have to
|
||||
// default it to a sane (default) value in the internal type.
|
||||
out.EncryptionAlgorithm = kubeadm.EncryptionAlgorithmRSA
|
||||
out.EncryptionAlgorithm = kubeadm.EncryptionAlgorithmRSA2048
|
||||
return autoConvert_v1beta3_ClusterConfiguration_To_kubeadm_ClusterConfiguration(in, out, s)
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ const (
|
||||
DefaultImagePullPolicy = corev1.PullIfNotPresent
|
||||
|
||||
// DefaultEncryptionAlgorithm is the default encryption algorithm.
|
||||
DefaultEncryptionAlgorithm = EncryptionAlgorithmRSA
|
||||
DefaultEncryptionAlgorithm = EncryptionAlgorithmRSA2048
|
||||
)
|
||||
|
||||
func addDefaultingFuncs(scheme *runtime.Scheme) error {
|
||||
|
@ -33,8 +33,7 @@ limitations under the License.
|
||||
// The change applies to `ClusterConfiguration` - `APIServer.ExtraArgs, `ControllerManager.ExtraArgs`,
|
||||
// `Scheduler.ExtraArgs`, `Etcd.Local.ExtraArgs`. Also to `NodeRegistrationOptions.KubeletExtraArgs`.
|
||||
// - Add `ClusterConfiguration.EncryptionAlgorithm` that can be used to set the asymmetric encryption algorithm
|
||||
// used for this cluster's keys and certificates. Can be "RSA" (default algorithm, key size is 2048) or
|
||||
// "ECDSA" (uses the P-256 elliptic curve).
|
||||
// used for this cluster's keys and certificates. Can be one of "RSA-2048" (default), "RSA-3072", "RSA-4096" or "ECDSA-P256".
|
||||
// - Add `ClusterConfiguration.DNS.Disabled` and `ClusterConfiguration.Proxy.Disabled` that can be used to disable
|
||||
// the CoreDNS and kube-proxy addons during cluster initialization. Skipping the related addons phases,
|
||||
// during cluster creation will set the same fields to `false`.
|
||||
|
@ -149,7 +149,7 @@ type ClusterConfiguration struct {
|
||||
ClusterName string `json:"clusterName,omitempty"`
|
||||
|
||||
// EncryptionAlgorithm holds the type of asymmetric encryption algorithm used for keys and certificates.
|
||||
// Can be "RSA" (default algorithm, key size is 2048) or "ECDSA" (uses the P-256 elliptic curve).
|
||||
// Can be one of "RSA-2048" (default), "RSA-3072", "RSA-4096" or "ECDSA-P256".
|
||||
// +optional
|
||||
EncryptionAlgorithm EncryptionAlgorithmType `json:"encryptionAlgorithm,omitempty"`
|
||||
}
|
||||
@ -549,10 +549,14 @@ type EnvVar struct {
|
||||
type EncryptionAlgorithmType string
|
||||
|
||||
const (
|
||||
// EncryptionAlgorithmECDSA defines the ECDSA encryption algorithm type.
|
||||
EncryptionAlgorithmECDSA EncryptionAlgorithmType = "ECDSA"
|
||||
// EncryptionAlgorithmRSA defines the RSA encryption algorithm type.
|
||||
EncryptionAlgorithmRSA EncryptionAlgorithmType = "RSA"
|
||||
// EncryptionAlgorithmECDSAP256 defines the ECDSA encryption algorithm type with curve P256.
|
||||
EncryptionAlgorithmECDSAP256 EncryptionAlgorithmType = "ECDSA-P256"
|
||||
// EncryptionAlgorithmRSA2048 defines the RSA encryption algorithm type with key size 2048 bits.
|
||||
EncryptionAlgorithmRSA2048 EncryptionAlgorithmType = "RSA-2048"
|
||||
// EncryptionAlgorithmRSA3072 defines the RSA encryption algorithm type with key size 3072 bits.
|
||||
EncryptionAlgorithmRSA3072 EncryptionAlgorithmType = "RSA-3072"
|
||||
// EncryptionAlgorithmRSA4096 defines the RSA encryption algorithm type with key size 4096 bits.
|
||||
EncryptionAlgorithmRSA4096 EncryptionAlgorithmType = "RSA-4096"
|
||||
)
|
||||
|
||||
// Timeouts holds various timeouts that apply to kubeadm commands.
|
||||
|
@ -73,7 +73,7 @@ func ValidateClusterConfiguration(c *kubeadm.ClusterConfiguration) field.ErrorLi
|
||||
allErrs = append(allErrs, ValidateHostPort(c.ControlPlaneEndpoint, field.NewPath("controlPlaneEndpoint"))...)
|
||||
allErrs = append(allErrs, ValidateImageRepository(c.ImageRepository, field.NewPath("imageRepository"))...)
|
||||
allErrs = append(allErrs, ValidateEtcd(&c.Etcd, field.NewPath("etcd"))...)
|
||||
allErrs = append(allErrs, ValidateEncryptionAlgorithm(string(c.EncryptionAlgorithm), field.NewPath("encryptionAlgorithm"))...)
|
||||
allErrs = append(allErrs, ValidateEncryptionAlgorithm(c.EncryptionAlgorithm, field.NewPath("encryptionAlgorithm"))...)
|
||||
allErrs = append(allErrs, componentconfigs.Validate(c)...)
|
||||
return allErrs
|
||||
}
|
||||
@ -341,11 +341,16 @@ func ValidateEtcd(e *kubeadm.Etcd, fldPath *field.Path) field.ErrorList {
|
||||
}
|
||||
|
||||
// ValidateEncryptionAlgorithm validates the public key algorithm
|
||||
func ValidateEncryptionAlgorithm(algo string, fldPath *field.Path) field.ErrorList {
|
||||
func ValidateEncryptionAlgorithm(algo kubeadm.EncryptionAlgorithmType, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if algo != string(kubeadm.EncryptionAlgorithmRSA) && algo != string(kubeadm.EncryptionAlgorithmECDSA) {
|
||||
msg := fmt.Sprintf("Invalid encryption algorithm. Must be %q or %q",
|
||||
kubeadm.EncryptionAlgorithmRSA, kubeadm.EncryptionAlgorithmECDSA)
|
||||
knownAlgorithms := sets.New(
|
||||
kubeadm.EncryptionAlgorithmECDSAP256,
|
||||
kubeadm.EncryptionAlgorithmRSA2048,
|
||||
kubeadm.EncryptionAlgorithmRSA3072,
|
||||
kubeadm.EncryptionAlgorithmRSA4096,
|
||||
)
|
||||
if !knownAlgorithms.Has(algo) {
|
||||
msg := fmt.Sprintf("Invalid encryption algorithm %q. Must be one of %v", algo, sets.List(knownAlgorithms))
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, algo, msg))
|
||||
}
|
||||
return allErrs
|
||||
|
@ -515,7 +515,7 @@ func TestValidateInitConfiguration(t *testing.T) {
|
||||
DNSDomain: "cluster.local",
|
||||
},
|
||||
CertificatesDir: "/some/cert/dir",
|
||||
EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmRSA,
|
||||
EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmRSA2048,
|
||||
},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: nodename, CRISocket: criPath},
|
||||
}, false},
|
||||
@ -531,7 +531,7 @@ func TestValidateInitConfiguration(t *testing.T) {
|
||||
DNSDomain: "cluster.local",
|
||||
},
|
||||
CertificatesDir: "/some/cert/dir",
|
||||
EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmRSA,
|
||||
EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmRSA2048,
|
||||
},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: nodename, CRISocket: criPath},
|
||||
}, false},
|
||||
@ -547,7 +547,7 @@ func TestValidateInitConfiguration(t *testing.T) {
|
||||
DNSDomain: "cluster.local",
|
||||
},
|
||||
CertificatesDir: "/some/other/cert/dir",
|
||||
EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmRSA,
|
||||
EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmRSA2048,
|
||||
},
|
||||
}, false},
|
||||
{"valid InitConfiguration with incorrect IPv4 pod subnet",
|
||||
@ -563,7 +563,7 @@ func TestValidateInitConfiguration(t *testing.T) {
|
||||
PodSubnet: "10.0.1.15",
|
||||
},
|
||||
CertificatesDir: "/some/other/cert/dir",
|
||||
EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmRSA,
|
||||
EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmRSA2048,
|
||||
},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: nodename, CRISocket: criPath},
|
||||
}, false},
|
||||
@ -586,7 +586,7 @@ func TestValidateInitConfiguration(t *testing.T) {
|
||||
PodSubnet: "10.0.1.15/16",
|
||||
},
|
||||
CertificatesDir: "/some/other/cert/dir",
|
||||
EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmRSA,
|
||||
EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmRSA2048,
|
||||
},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: nodename, CRISocket: criPath},
|
||||
}, true},
|
||||
@ -608,7 +608,7 @@ func TestValidateInitConfiguration(t *testing.T) {
|
||||
DNSDomain: "cluster.local",
|
||||
},
|
||||
CertificatesDir: "/some/other/cert/dir",
|
||||
EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmECDSA,
|
||||
EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmECDSAP256,
|
||||
},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: nodename, CRISocket: criPath},
|
||||
}, true},
|
||||
@ -1197,11 +1197,13 @@ func TestValidateEtcd(t *testing.T) {
|
||||
func TestValidateEncryptionAlgorithm(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
algo string
|
||||
algo kubeadmapi.EncryptionAlgorithmType
|
||||
expectedErrors bool
|
||||
}{
|
||||
{name: "valid RSA", algo: string(kubeadmapi.EncryptionAlgorithmRSA), expectedErrors: false},
|
||||
{name: "valid ECDSA", algo: string(kubeadmapi.EncryptionAlgorithmECDSA), expectedErrors: false},
|
||||
{name: "valid RSA-2048", algo: kubeadmapi.EncryptionAlgorithmRSA2048, expectedErrors: false},
|
||||
{name: "valid RSA-3072", algo: kubeadmapi.EncryptionAlgorithmRSA3072, expectedErrors: false},
|
||||
{name: "valid RSA-4096", algo: kubeadmapi.EncryptionAlgorithmRSA4096, expectedErrors: false},
|
||||
{name: "valid ECDSA-P256", algo: kubeadmapi.EncryptionAlgorithmECDSAP256, expectedErrors: false},
|
||||
{name: "invalid algorithm", algo: "foo", expectedErrors: true},
|
||||
{name: "empty algorithm returns an error", algo: "", expectedErrors: true},
|
||||
}
|
||||
|
@ -43,8 +43,9 @@ const (
|
||||
// InitFeatureGates are the default feature gates for the init command
|
||||
var InitFeatureGates = FeatureList{
|
||||
PublicKeysECDSA: {
|
||||
FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Deprecated},
|
||||
DeprecationMessage: "The PublicKeysECDSA feature gate is deprecated and will be removed after the feature 'ClusterConfiguration.EncryptionAlgorithm' is added.",
|
||||
FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Deprecated},
|
||||
DeprecationMessage: "The PublicKeysECDSA feature gate is deprecated and will be removed when v1beta3 is removed." +
|
||||
" v1beta4 supports a new option 'ClusterConfiguration.EncryptionAlgorithm'.",
|
||||
},
|
||||
RootlessControlPlane: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}},
|
||||
EtcdLearnerMode: {FeatureSpec: featuregate.FeatureSpec{Default: true, PreRelease: featuregate.Beta}},
|
||||
|
@ -262,7 +262,7 @@ func TestCreateServiceAccountKeyAndPublicKeyFiles(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
err := CreateServiceAccountKeyAndPublicKeyFiles(dir, kubeadmapi.EncryptionAlgorithmRSA)
|
||||
err := CreateServiceAccountKeyAndPublicKeyFiles(dir, kubeadmapi.EncryptionAlgorithmRSA2048)
|
||||
if (err != nil) != tt.expectedErr {
|
||||
t.Fatalf("expected error: %v, got: %v, error: %v", tt.expectedErr, err != nil, err)
|
||||
} else if tt.expectedErr {
|
||||
|
@ -57,7 +57,6 @@ const (
|
||||
CertificateBlockType = "CERTIFICATE"
|
||||
// RSAPrivateKeyBlockType is a possible value for pem.Block.Type.
|
||||
RSAPrivateKeyBlockType = "RSA PRIVATE KEY"
|
||||
rsaKeySize = 2048
|
||||
)
|
||||
|
||||
// CertConfig is a wrapper around certutil.Config extending it with EncryptionAlgorithm.
|
||||
@ -608,12 +607,32 @@ func EncodePublicKeyPEM(key crypto.PublicKey) ([]byte, error) {
|
||||
// NewPrivateKey returns a new private key.
|
||||
var NewPrivateKey = GeneratePrivateKey
|
||||
|
||||
// rsaKeySizeFromAlgorithmType takes a known RSA algorithm defined in the kubeadm API
|
||||
// an returns its key size. For unknown types it returns 0. For an empty type it returns
|
||||
// the default size of 2048.
|
||||
func rsaKeySizeFromAlgorithmType(keyType kubeadmapi.EncryptionAlgorithmType) int {
|
||||
switch keyType {
|
||||
case kubeadmapi.EncryptionAlgorithmRSA2048, "":
|
||||
return 2048
|
||||
case kubeadmapi.EncryptionAlgorithmRSA3072:
|
||||
return 3072
|
||||
case kubeadmapi.EncryptionAlgorithmRSA4096:
|
||||
return 4096
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// GeneratePrivateKey is the default function for generating private keys.
|
||||
func GeneratePrivateKey(keyType kubeadmapi.EncryptionAlgorithmType) (crypto.Signer, error) {
|
||||
if keyType == kubeadmapi.EncryptionAlgorithmECDSA {
|
||||
if keyType == kubeadmapi.EncryptionAlgorithmECDSAP256 {
|
||||
return ecdsa.GenerateKey(elliptic.P256(), cryptorand.Reader)
|
||||
}
|
||||
|
||||
rsaKeySize := rsaKeySizeFromAlgorithmType(keyType)
|
||||
if rsaKeySize == 0 {
|
||||
return nil, errors.Errorf("cannot obtain key size from unknown RSA algorithm: %q", keyType)
|
||||
}
|
||||
return rsa.GenerateKey(cryptorand.Reader, rsaKeySize)
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ func TestMain(m *testing.M) {
|
||||
Config: certutil.Config{
|
||||
CommonName: "Root CA 1",
|
||||
},
|
||||
EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmRSA,
|
||||
EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmRSA2048,
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Failed generating Root CA: %v", err))
|
||||
@ -141,7 +141,7 @@ func TestHasServerAuth(t *testing.T) {
|
||||
CommonName: "test",
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
},
|
||||
EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmECDSA,
|
||||
EncryptionAlgorithm: kubeadmapi.EncryptionAlgorithmECDSAP256,
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
@ -940,3 +940,24 @@ func TestVerifyCertChain(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRSAKeySizeFromAlgorithmType(t *testing.T) {
|
||||
var tests = []struct {
|
||||
algorithm kubeadmapi.EncryptionAlgorithmType
|
||||
expectedSize int
|
||||
}{
|
||||
{algorithm: "unknown", expectedSize: 0},
|
||||
{algorithm: "", expectedSize: 2048},
|
||||
{algorithm: kubeadmapi.EncryptionAlgorithmRSA2048, expectedSize: 2048},
|
||||
{algorithm: kubeadmapi.EncryptionAlgorithmRSA3072, expectedSize: 3072},
|
||||
{algorithm: kubeadmapi.EncryptionAlgorithmRSA4096, expectedSize: 4096},
|
||||
}
|
||||
for _, rt := range tests {
|
||||
t.Run(string(rt.algorithm), func(t *testing.T) {
|
||||
size := rsaKeySizeFromAlgorithmType(rt.algorithm)
|
||||
if size != rt.expectedSize {
|
||||
t.Errorf("expected size: %d, got: %d", rt.expectedSize, size)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ func newPrivateKey(keyType kubeadmapi.EncryptionAlgorithmType) (crypto.Signer, e
|
||||
|
||||
keyName := ""
|
||||
switch keyType {
|
||||
case kubeadmapi.EncryptionAlgorithmECDSA:
|
||||
case kubeadmapi.EncryptionAlgorithmECDSAP256:
|
||||
ecdsa++
|
||||
keyName = fmt.Sprintf("%d.ecdsa", ecdsa)
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user