From 7af48bd5598e61357cdb9b31dd57de6479b1ce7c Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 31 Jan 2024 16:49:59 +0400 Subject: [PATCH] feat: use RSA key for kube-apiserver service account key Fixes #8111 Starting with 1.7, use RSA instead of ECDSA. RSA is way slower, but it has better support with other providers. Signed-off-by: Andrey Smirnov --- hack/release.toml | 6 ++ pkg/machinery/config/contract.go | 6 ++ pkg/machinery/config/contract_test.go | 57 +++++++++++++++++++ .../config/generate/secrets/bundle.go | 23 ++++++-- 4 files changed, 86 insertions(+), 6 deletions(-) diff --git a/hack/release.toml b/hack/release.toml index 20a497c316..aa9fe19c68 100644 --- a/hack/release.toml +++ b/hack/release.toml @@ -49,6 +49,12 @@ machine: features: localDNS: false ``` +""" + + [notes.rsa-service-account] + title = "Kubernetes API Server Service Account Key" + description = """\ +Talos Linux starting from this release uses RSA key for Kubernetes API Server Service Account instead of ECDSA key to provide better compatibility with external OpenID Connect implementations. """ [make_deps] diff --git a/pkg/machinery/config/contract.go b/pkg/machinery/config/contract.go index 354360dc1e..104a6b637a 100644 --- a/pkg/machinery/config/contract.go +++ b/pkg/machinery/config/contract.go @@ -24,6 +24,7 @@ type VersionContract struct { // Well-known Talos version contracts. var ( TalosVersionCurrent = (*VersionContract)(nil) + TalosVersion1_7 = &VersionContract{1, 7} TalosVersion1_6 = &VersionContract{1, 6} TalosVersion1_5 = &VersionContract{1, 5} TalosVersion1_4 = &VersionContract{1, 4} @@ -184,3 +185,8 @@ func (contract *VersionContract) KubePrismEnabled() bool { func (contract *VersionContract) LocalDNSEnabled() bool { return contract.Greater(TalosVersion1_6) } + +// UseRSAServiceAccountKey returns true if version of Talos should use RSA Service Account key for the kube-apiserver. +func (contract *VersionContract) UseRSAServiceAccountKey() bool { + return contract.Greater(TalosVersion1_6) +} diff --git a/pkg/machinery/config/contract_test.go b/pkg/machinery/config/contract_test.go index 0149526a15..ab77f5b5f4 100644 --- a/pkg/machinery/config/contract_test.go +++ b/pkg/machinery/config/contract_test.go @@ -67,6 +67,35 @@ func TestContractCurrent(t *testing.T) { assert.True(t, contract.SecretboxEncryptionSupported()) assert.True(t, contract.DiskQuotaSupportEnabled()) assert.True(t, contract.KubePrismEnabled()) + assert.True(t, contract.LocalDNSEnabled()) + assert.True(t, contract.UseRSAServiceAccountKey()) +} + +func TestContract1_7(t *testing.T) { + contract := config.TalosVersion1_7 + + assert.True(t, contract.SupportsAggregatorCA()) + assert.True(t, contract.SupportsECDSAKeys()) + assert.True(t, contract.SupportsServiceAccount()) + assert.True(t, contract.SupportsRBACFeature()) + assert.True(t, contract.SupportsDynamicCertSANs()) + assert.True(t, contract.SupportsECDSASHA256()) + assert.True(t, contract.ClusterDiscoveryEnabled()) + assert.False(t, contract.PodSecurityPolicyEnabled()) + assert.True(t, contract.PodSecurityAdmissionEnabled()) + assert.True(t, contract.StableHostnameEnabled()) + assert.True(t, contract.KubeletDefaultRuntimeSeccompProfileEnabled()) + assert.False(t, contract.KubernetesAlternateImageRegistries()) + assert.True(t, contract.KubernetesAllowSchedulingOnControlPlanes()) + assert.True(t, contract.KubernetesDiscoveryBackendDisabled()) + assert.True(t, contract.ApidExtKeyUsageCheckEnabled()) + assert.True(t, contract.APIServerAuditPolicySupported()) + assert.True(t, contract.KubeletManifestsDirectoryDisabled()) + assert.True(t, contract.SecretboxEncryptionSupported()) + assert.True(t, contract.DiskQuotaSupportEnabled()) + assert.True(t, contract.KubePrismEnabled()) + assert.True(t, contract.LocalDNSEnabled()) + assert.True(t, contract.UseRSAServiceAccountKey()) } func TestContract1_6(t *testing.T) { @@ -92,6 +121,8 @@ func TestContract1_6(t *testing.T) { assert.True(t, contract.SecretboxEncryptionSupported()) assert.True(t, contract.DiskQuotaSupportEnabled()) assert.True(t, contract.KubePrismEnabled()) + assert.False(t, contract.LocalDNSEnabled()) + assert.False(t, contract.UseRSAServiceAccountKey()) } func TestContract1_5(t *testing.T) { @@ -117,6 +148,8 @@ func TestContract1_5(t *testing.T) { assert.True(t, contract.SecretboxEncryptionSupported()) assert.True(t, contract.DiskQuotaSupportEnabled()) assert.False(t, contract.KubePrismEnabled()) + assert.False(t, contract.LocalDNSEnabled()) + assert.False(t, contract.UseRSAServiceAccountKey()) } func TestContract1_4(t *testing.T) { @@ -142,6 +175,8 @@ func TestContract1_4(t *testing.T) { assert.True(t, contract.SecretboxEncryptionSupported()) assert.False(t, contract.DiskQuotaSupportEnabled()) assert.False(t, contract.KubePrismEnabled()) + assert.False(t, contract.LocalDNSEnabled()) + assert.False(t, contract.UseRSAServiceAccountKey()) } func TestContract1_3(t *testing.T) { @@ -167,6 +202,8 @@ func TestContract1_3(t *testing.T) { assert.True(t, contract.SecretboxEncryptionSupported()) assert.False(t, contract.DiskQuotaSupportEnabled()) assert.False(t, contract.KubePrismEnabled()) + assert.False(t, contract.LocalDNSEnabled()) + assert.False(t, contract.UseRSAServiceAccountKey()) } func TestContract1_2(t *testing.T) { @@ -192,6 +229,8 @@ func TestContract1_2(t *testing.T) { assert.False(t, contract.SecretboxEncryptionSupported()) assert.False(t, contract.DiskQuotaSupportEnabled()) assert.False(t, contract.KubePrismEnabled()) + assert.False(t, contract.LocalDNSEnabled()) + assert.False(t, contract.UseRSAServiceAccountKey()) } func TestContract1_1(t *testing.T) { @@ -217,6 +256,8 @@ func TestContract1_1(t *testing.T) { assert.False(t, contract.SecretboxEncryptionSupported()) assert.False(t, contract.DiskQuotaSupportEnabled()) assert.False(t, contract.KubePrismEnabled()) + assert.False(t, contract.LocalDNSEnabled()) + assert.False(t, contract.UseRSAServiceAccountKey()) } func TestContract1_0(t *testing.T) { @@ -242,6 +283,8 @@ func TestContract1_0(t *testing.T) { assert.False(t, contract.SecretboxEncryptionSupported()) assert.False(t, contract.DiskQuotaSupportEnabled()) assert.False(t, contract.KubePrismEnabled()) + assert.False(t, contract.LocalDNSEnabled()) + assert.False(t, contract.UseRSAServiceAccountKey()) } func TestContract0_14(t *testing.T) { @@ -267,6 +310,8 @@ func TestContract0_14(t *testing.T) { assert.False(t, contract.SecretboxEncryptionSupported()) assert.False(t, contract.DiskQuotaSupportEnabled()) assert.False(t, contract.KubePrismEnabled()) + assert.False(t, contract.LocalDNSEnabled()) + assert.False(t, contract.UseRSAServiceAccountKey()) } func TestContract0_13(t *testing.T) { @@ -292,6 +337,8 @@ func TestContract0_13(t *testing.T) { assert.False(t, contract.SecretboxEncryptionSupported()) assert.False(t, contract.DiskQuotaSupportEnabled()) assert.False(t, contract.KubePrismEnabled()) + assert.False(t, contract.LocalDNSEnabled()) + assert.False(t, contract.UseRSAServiceAccountKey()) } func TestContract0_12(t *testing.T) { @@ -317,6 +364,8 @@ func TestContract0_12(t *testing.T) { assert.False(t, contract.SecretboxEncryptionSupported()) assert.False(t, contract.DiskQuotaSupportEnabled()) assert.False(t, contract.KubePrismEnabled()) + assert.False(t, contract.LocalDNSEnabled()) + assert.False(t, contract.UseRSAServiceAccountKey()) } func TestContract0_11(t *testing.T) { @@ -342,6 +391,8 @@ func TestContract0_11(t *testing.T) { assert.False(t, contract.SecretboxEncryptionSupported()) assert.False(t, contract.DiskQuotaSupportEnabled()) assert.False(t, contract.KubePrismEnabled()) + assert.False(t, contract.LocalDNSEnabled()) + assert.False(t, contract.UseRSAServiceAccountKey()) } func TestContract0_10(t *testing.T) { @@ -367,6 +418,8 @@ func TestContract0_10(t *testing.T) { assert.False(t, contract.SecretboxEncryptionSupported()) assert.False(t, contract.DiskQuotaSupportEnabled()) assert.False(t, contract.KubePrismEnabled()) + assert.False(t, contract.LocalDNSEnabled()) + assert.False(t, contract.UseRSAServiceAccountKey()) } func TestContract0_9(t *testing.T) { @@ -392,6 +445,8 @@ func TestContract0_9(t *testing.T) { assert.False(t, contract.SecretboxEncryptionSupported()) assert.False(t, contract.DiskQuotaSupportEnabled()) assert.False(t, contract.KubePrismEnabled()) + assert.False(t, contract.LocalDNSEnabled()) + assert.False(t, contract.UseRSAServiceAccountKey()) } func TestContract0_8(t *testing.T) { @@ -417,4 +472,6 @@ func TestContract0_8(t *testing.T) { assert.False(t, contract.SecretboxEncryptionSupported()) assert.False(t, contract.DiskQuotaSupportEnabled()) assert.False(t, contract.KubePrismEnabled()) + assert.False(t, contract.LocalDNSEnabled()) + assert.False(t, contract.UseRSAServiceAccountKey()) } diff --git a/pkg/machinery/config/generate/secrets/bundle.go b/pkg/machinery/config/generate/secrets/bundle.go index 922308e82f..f8a175d59a 100644 --- a/pkg/machinery/config/generate/secrets/bundle.go +++ b/pkg/machinery/config/generate/secrets/bundle.go @@ -252,13 +252,24 @@ func (bundle *Bundle) populate(versionContract *config.VersionContract) error { } if versionContract.SupportsServiceAccount() && bundle.Certs.K8sServiceAccount == nil { - serviceAccount, err := x509.NewECDSAKey() - if err != nil { - return err - } + if versionContract.UseRSAServiceAccountKey() { + serviceAccount, err := x509.NewRSAKey() + if err != nil { + return err + } - bundle.Certs.K8sServiceAccount = &x509.PEMEncodedKey{ - Key: serviceAccount.KeyPEM, + bundle.Certs.K8sServiceAccount = &x509.PEMEncodedKey{ + Key: serviceAccount.KeyPEM, + } + } else { + serviceAccount, err := x509.NewECDSAKey() + if err != nil { + return err + } + + bundle.Certs.K8sServiceAccount = &x509.PEMEncodedKey{ + Key: serviceAccount.KeyPEM, + } } }