Skip to content

Commit 109f5db

Browse files
author
Dmitry Rozhkov
committed
kubeadm: allow creating a cluster with ECDSA keys
The selected key type is defined by kubeadm's --feature-gates option: if it contains PublicKeysECDSA=true then ECDSA keys will be generated and used. By default RSA keys are used still. Signed-off-by: Dmitry Rozhkov <[email protected]>
1 parent ac25069 commit 109f5db

File tree

22 files changed

+241
-133
lines changed

22 files changed

+241
-133
lines changed

cmd/kubeadm/app/apis/kubeadm/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ go_library(
1919
],
2020
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm",
2121
deps = [
22+
"//cmd/kubeadm/app/features:go_default_library",
2223
"//staging/src/k8s.io/api/core/v1:go_default_library",
2324
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
2425
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",

cmd/kubeadm/app/apis/kubeadm/types.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ limitations under the License.
1717
package kubeadm
1818

1919
import (
20+
"crypto/x509"
21+
2022
v1 "k8s.io/api/core/v1"
2123
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24+
"k8s.io/kubernetes/cmd/kubeadm/app/features"
2225

2326
"k8s.io/apimachinery/pkg/runtime/schema"
2427
)
@@ -400,6 +403,15 @@ func (cfg *ClusterConfiguration) GetControlPlaneImageRepository() string {
400403
return cfg.ImageRepository
401404
}
402405

406+
// PublicKeyAlgorithm returns the type of encryption keys used in the cluster.
407+
func (cfg *ClusterConfiguration) PublicKeyAlgorithm() x509.PublicKeyAlgorithm {
408+
if features.Enabled(cfg.FeatureGates, features.PublicKeysECDSA) {
409+
return x509.ECDSA
410+
}
411+
412+
return x509.RSA
413+
}
414+
403415
// HostPathMount contains elements describing volumes that are mounted from the
404416
// host.
405417
type HostPathMount struct {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ func runCertsSa(c workflow.RunData) error {
200200
}
201201

202202
// create the new service account key (or use existing)
203-
return certsphase.CreateServiceAccountKeyAndPublicKeyFiles(data.CertificateWriteDir())
203+
return certsphase.CreateServiceAccountKeyAndPublicKeyFiles(data.CertificateWriteDir(), data.Cfg().ClusterConfiguration.PublicKeyAlgorithm())
204204
}
205205

206206
func runCerts(c workflow.RunData) error {

cmd/kubeadm/app/features/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ go_test(
3535
srcs = ["features_test.go"],
3636
embed = [":go_default_library"],
3737
deps = [
38-
"//cmd/kubeadm/app/constants:go_default_library",
38+
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
3939
"//staging/src/k8s.io/component-base/featuregate:go_default_library",
4040
],
4141
)

cmd/kubeadm/app/features/features.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,14 @@ import (
3030
const (
3131
// IPv6DualStack is expected to be alpha in v1.16
3232
IPv6DualStack = "IPv6DualStack"
33+
// PublicKeysECDSA is expected to be alpha in v1.19
34+
PublicKeysECDSA = "PublicKeysECDSA"
3335
)
3436

3537
// InitFeatureGates are the default feature gates for the init command
3638
var InitFeatureGates = FeatureList{
37-
IPv6DualStack: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}},
39+
IPv6DualStack: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}},
40+
PublicKeysECDSA: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}},
3841
}
3942

4043
// Feature represents a feature being gated

cmd/kubeadm/app/features/features_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import (
2020
"reflect"
2121
"testing"
2222

23+
"k8s.io/apimachinery/pkg/util/version"
2324
"k8s.io/component-base/featuregate"
24-
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
2525
)
2626

2727
func TestKnownFeatures(t *testing.T) {
@@ -129,7 +129,7 @@ func TestNewFeatureGate(t *testing.T) {
129129
func TestValidateVersion(t *testing.T) {
130130
var someFeatures = FeatureList{
131131
"feature1": {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Beta}},
132-
"feature2": {FeatureSpec: featuregate.FeatureSpec{Default: true, PreRelease: featuregate.Alpha}, MinimumVersion: constants.MinimumControlPlaneVersion.WithPreRelease("alpha.1")},
132+
"feature2": {FeatureSpec: featuregate.FeatureSpec{Default: true, PreRelease: featuregate.Alpha}, MinimumVersion: version.MustParseSemantic("v1.17.0").WithPreRelease("alpha.1")},
133133
}
134134

135135
var tests = []struct {
@@ -146,7 +146,7 @@ func TestValidateVersion(t *testing.T) {
146146
{
147147
name: "min version but correct value given",
148148
requestedFeatures: map[string]bool{"feature2": true},
149-
requestedVersion: constants.MinimumControlPlaneVersion.String(),
149+
requestedVersion: "v1.17.0",
150150
expectedError: false,
151151
},
152152
{

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

Lines changed: 58 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import (
2828
"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
2929
)
3030

31-
type configMutatorsFunc func(*kubeadmapi.InitConfiguration, *certutil.Config) error
31+
type configMutatorsFunc func(*kubeadmapi.InitConfiguration, *pkiutil.CertConfig) error
3232

3333
// KubeadmCert represents a certificate that Kubeadm will create to function properly.
3434
type KubeadmCert struct {
@@ -39,17 +39,18 @@ type KubeadmCert struct {
3939
// Some attributes will depend on the InitConfiguration, only known at runtime.
4040
// These functions will be run in series, passed both the InitConfiguration and a cert Config.
4141
configMutators []configMutatorsFunc
42-
config certutil.Config
42+
config pkiutil.CertConfig
4343
}
4444

4545
// GetConfig returns the definition for the given cert given the provided InitConfiguration
46-
func (k *KubeadmCert) GetConfig(ic *kubeadmapi.InitConfiguration) (*certutil.Config, error) {
46+
func (k *KubeadmCert) GetConfig(ic *kubeadmapi.InitConfiguration) (*pkiutil.CertConfig, error) {
4747
for _, f := range k.configMutators {
4848
if err := f(ic, &k.config); err != nil {
4949
return nil, err
5050
}
5151
}
5252

53+
k.config.PublicKeyAlgorithm = ic.ClusterConfiguration.PublicKeyAlgorithm()
5354
return &k.config, nil
5455
}
5556

@@ -239,8 +240,10 @@ var (
239240
Name: "ca",
240241
LongName: "self-signed Kubernetes CA to provision identities for other Kubernetes components",
241242
BaseName: kubeadmconstants.CACertAndKeyBaseName,
242-
config: certutil.Config{
243-
CommonName: "kubernetes",
243+
config: pkiutil.CertConfig{
244+
Config: certutil.Config{
245+
CommonName: "kubernetes",
246+
},
244247
},
245248
}
246249
// KubeadmCertAPIServer is the definition of the cert used to serve the Kubernetes API.
@@ -249,9 +252,11 @@ var (
249252
LongName: "certificate for serving the Kubernetes API",
250253
BaseName: kubeadmconstants.APIServerCertAndKeyBaseName,
251254
CAName: "ca",
252-
config: certutil.Config{
253-
CommonName: kubeadmconstants.APIServerCertCommonName,
254-
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
255+
config: pkiutil.CertConfig{
256+
Config: certutil.Config{
257+
CommonName: kubeadmconstants.APIServerCertCommonName,
258+
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
259+
},
255260
},
256261
configMutators: []configMutatorsFunc{
257262
makeAltNamesMutator(pkiutil.GetAPIServerAltNames),
@@ -263,10 +268,12 @@ var (
263268
LongName: "certificate for the API server to connect to kubelet",
264269
BaseName: kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName,
265270
CAName: "ca",
266-
config: certutil.Config{
267-
CommonName: kubeadmconstants.APIServerKubeletClientCertCommonName,
268-
Organization: []string{kubeadmconstants.SystemPrivilegedGroup},
269-
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
271+
config: pkiutil.CertConfig{
272+
Config: certutil.Config{
273+
CommonName: kubeadmconstants.APIServerKubeletClientCertCommonName,
274+
Organization: []string{kubeadmconstants.SystemPrivilegedGroup},
275+
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
276+
},
270277
},
271278
}
272279

@@ -275,8 +282,10 @@ var (
275282
Name: "front-proxy-ca",
276283
LongName: "self-signed CA to provision identities for front proxy",
277284
BaseName: kubeadmconstants.FrontProxyCACertAndKeyBaseName,
278-
config: certutil.Config{
279-
CommonName: "front-proxy-ca",
285+
config: pkiutil.CertConfig{
286+
Config: certutil.Config{
287+
CommonName: "front-proxy-ca",
288+
},
280289
},
281290
}
282291

@@ -286,9 +295,11 @@ var (
286295
BaseName: kubeadmconstants.FrontProxyClientCertAndKeyBaseName,
287296
LongName: "certificate for the front proxy client",
288297
CAName: "front-proxy-ca",
289-
config: certutil.Config{
290-
CommonName: kubeadmconstants.FrontProxyClientCertCommonName,
291-
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
298+
config: pkiutil.CertConfig{
299+
Config: certutil.Config{
300+
CommonName: kubeadmconstants.FrontProxyClientCertCommonName,
301+
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
302+
},
292303
},
293304
}
294305

@@ -297,8 +308,10 @@ var (
297308
Name: "etcd-ca",
298309
LongName: "self-signed CA to provision identities for etcd",
299310
BaseName: kubeadmconstants.EtcdCACertAndKeyBaseName,
300-
config: certutil.Config{
301-
CommonName: "etcd-ca",
311+
config: pkiutil.CertConfig{
312+
Config: certutil.Config{
313+
CommonName: "etcd-ca",
314+
},
302315
},
303316
}
304317
// KubeadmCertEtcdServer is the definition of the cert used to serve etcd to clients.
@@ -307,12 +320,14 @@ var (
307320
LongName: "certificate for serving etcd",
308321
BaseName: kubeadmconstants.EtcdServerCertAndKeyBaseName,
309322
CAName: "etcd-ca",
310-
config: certutil.Config{
311-
// TODO: etcd 3.2 introduced an undocumented requirement for ClientAuth usage on the
312-
// server cert: https://github.com/coreos/etcd/issues/9785#issuecomment-396715692
313-
// Once the upstream issue is resolved, this should be returned to only allowing
314-
// ServerAuth usage.
315-
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
323+
config: pkiutil.CertConfig{
324+
Config: certutil.Config{
325+
// TODO: etcd 3.2 introduced an undocumented requirement for ClientAuth usage on the
326+
// server cert: https://github.com/coreos/etcd/issues/9785#issuecomment-396715692
327+
// Once the upstream issue is resolved, this should be returned to only allowing
328+
// ServerAuth usage.
329+
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
330+
},
316331
},
317332
configMutators: []configMutatorsFunc{
318333
makeAltNamesMutator(pkiutil.GetEtcdAltNames),
@@ -325,8 +340,10 @@ var (
325340
LongName: "certificate for etcd nodes to communicate with each other",
326341
BaseName: kubeadmconstants.EtcdPeerCertAndKeyBaseName,
327342
CAName: "etcd-ca",
328-
config: certutil.Config{
329-
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
343+
config: pkiutil.CertConfig{
344+
Config: certutil.Config{
345+
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
346+
},
330347
},
331348
configMutators: []configMutatorsFunc{
332349
makeAltNamesMutator(pkiutil.GetEtcdPeerAltNames),
@@ -339,10 +356,12 @@ var (
339356
LongName: "certificate for liveness probes to healthcheck etcd",
340357
BaseName: kubeadmconstants.EtcdHealthcheckClientCertAndKeyBaseName,
341358
CAName: "etcd-ca",
342-
config: certutil.Config{
343-
CommonName: kubeadmconstants.EtcdHealthcheckClientCertCommonName,
344-
Organization: []string{kubeadmconstants.SystemPrivilegedGroup},
345-
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
359+
config: pkiutil.CertConfig{
360+
Config: certutil.Config{
361+
CommonName: kubeadmconstants.EtcdHealthcheckClientCertCommonName,
362+
Organization: []string{kubeadmconstants.SystemPrivilegedGroup},
363+
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
364+
},
346365
},
347366
}
348367
// KubeadmCertEtcdAPIClient is the definition of the cert used by the API server to access etcd.
@@ -351,16 +370,18 @@ var (
351370
LongName: "certificate the apiserver uses to access etcd",
352371
BaseName: kubeadmconstants.APIServerEtcdClientCertAndKeyBaseName,
353372
CAName: "etcd-ca",
354-
config: certutil.Config{
355-
CommonName: kubeadmconstants.APIServerEtcdClientCertCommonName,
356-
Organization: []string{kubeadmconstants.SystemPrivilegedGroup},
357-
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
373+
config: pkiutil.CertConfig{
374+
Config: certutil.Config{
375+
CommonName: kubeadmconstants.APIServerEtcdClientCertCommonName,
376+
Organization: []string{kubeadmconstants.SystemPrivilegedGroup},
377+
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
378+
},
358379
},
359380
}
360381
)
361382

362383
func makeAltNamesMutator(f func(*kubeadmapi.InitConfiguration) (*certutil.AltNames, error)) configMutatorsFunc {
363-
return func(mc *kubeadmapi.InitConfiguration, cc *certutil.Config) error {
384+
return func(mc *kubeadmapi.InitConfiguration, cc *pkiutil.CertConfig) error {
364385
altNames, err := f(mc)
365386
if err != nil {
366387
return err
@@ -371,7 +392,7 @@ func makeAltNamesMutator(f func(*kubeadmapi.InitConfiguration) (*certutil.AltNam
371392
}
372393

373394
func setCommonNameToNodeName() configMutatorsFunc {
374-
return func(mc *kubeadmapi.InitConfiguration, cc *certutil.Config) error {
395+
return func(mc *kubeadmapi.InitConfiguration, cc *pkiutil.CertConfig) error {
375396
cc.CommonName = mc.NodeRegistration.Name
376397
return nil
377398
}

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727

2828
certutil "k8s.io/client-go/util/cert"
2929
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
30+
"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
3031
)
3132

3233
func TestCertListOrder(t *testing.T) {
@@ -160,16 +161,18 @@ func TestCreateCertificateChain(t *testing.T) {
160161

161162
caCfg := Certificates{
162163
{
163-
config: certutil.Config{},
164+
config: pkiutil.CertConfig{},
164165
Name: "test-ca",
165166
BaseName: "test-ca",
166167
},
167168
{
168-
config: certutil.Config{
169-
AltNames: certutil.AltNames{
170-
DNSNames: []string{"test-domain.space"},
169+
config: pkiutil.CertConfig{
170+
Config: certutil.Config{
171+
AltNames: certutil.AltNames{
172+
DNSNames: []string{"test-domain.space"},
173+
},
174+
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
171175
},
172-
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
173176
},
174177
configMutators: []configMutatorsFunc{
175178
setCommonNameToNodeName(),

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
"path/filepath"
2525

2626
"github.com/pkg/errors"
27-
certutil "k8s.io/client-go/util/cert"
2827
"k8s.io/client-go/util/keyutil"
2928
"k8s.io/klog"
3029
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
@@ -61,12 +60,12 @@ func CreatePKIAssets(cfg *kubeadmapi.InitConfiguration) error {
6160
fmt.Printf("[certs] Valid certificates and keys now exist in %q\n", cfg.CertificatesDir)
6261

6362
// Service accounts are not x509 certs, so handled separately
64-
return CreateServiceAccountKeyAndPublicKeyFiles(cfg.CertificatesDir)
63+
return CreateServiceAccountKeyAndPublicKeyFiles(cfg.CertificatesDir, cfg.ClusterConfiguration.PublicKeyAlgorithm())
6564
}
6665

6766
// CreateServiceAccountKeyAndPublicKeyFiles creates new public/private key files for signing service account users.
6867
// If the sa public/private key files already exist in the target folder, they are used only if evaluated equals; otherwise an error is returned.
69-
func CreateServiceAccountKeyAndPublicKeyFiles(certsDir string) error {
68+
func CreateServiceAccountKeyAndPublicKeyFiles(certsDir string, keyType x509.PublicKeyAlgorithm) error {
7069
klog.V(1).Infoln("creating new public/private key files for signing service account users")
7170
_, err := keyutil.PrivateKeyFromFile(filepath.Join(certsDir, kubeadmconstants.ServiceAccountPrivateKeyName))
7271
if err == nil {
@@ -80,7 +79,7 @@ func CreateServiceAccountKeyAndPublicKeyFiles(certsDir string) error {
8079
}
8180

8281
// The key does NOT exist, let's generate it now
83-
key, err := pkiutil.NewPrivateKey()
82+
key, err := pkiutil.NewPrivateKey(keyType)
8483
if err != nil {
8584
return err
8685
}
@@ -215,7 +214,7 @@ func writeCertificateAuthorityFilesIfNotExist(pkiDir string, baseName string, ca
215214
// If there already is a certificate file at the given path; kubeadm tries to load it and check if the values in the
216215
// existing and the expected certificate equals. If they do; kubeadm will just skip writing the file as it's up-to-date,
217216
// otherwise this function returns an error.
218-
func writeCertificateFilesIfNotExist(pkiDir string, baseName string, signingCert *x509.Certificate, cert *x509.Certificate, key crypto.Signer, cfg *certutil.Config) error {
217+
func writeCertificateFilesIfNotExist(pkiDir string, baseName string, signingCert *x509.Certificate, cert *x509.Certificate, key crypto.Signer, cfg *pkiutil.CertConfig) error {
219218

220219
// Checks if the signed certificate exists in the PKI directory
221220
if pkiutil.CertOrKeyExist(pkiDir, baseName) {
@@ -426,7 +425,7 @@ func validatePrivatePublicKey(l certKeyLocation) error {
426425

427426
// validateCertificateWithConfig makes sure that a given certificate is valid at
428427
// least for the SANs defined in the configuration.
429-
func validateCertificateWithConfig(cert *x509.Certificate, baseName string, cfg *certutil.Config) error {
428+
func validateCertificateWithConfig(cert *x509.Certificate, baseName string, cfg *pkiutil.CertConfig) error {
430429
for _, dnsName := range cfg.AltNames.DNSNames {
431430
if err := cert.VerifyHostname(dnsName); err != nil {
432431
return errors.Wrapf(err, "certificate %s is invalid", baseName)

0 commit comments

Comments
 (0)