Skip to content

Commit eefb585

Browse files
committed
Util changes
1 parent 41c4d39 commit eefb585

File tree

4 files changed

+117
-59
lines changed

4 files changed

+117
-59
lines changed

util/certs/certs.go

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,33 @@ package certs
1919

2020
import (
2121
"crypto"
22+
"crypto/ecdsa"
23+
"crypto/elliptic"
2224
"crypto/rand"
2325
"crypto/rsa"
2426
"crypto/x509"
2527
"encoding/pem"
28+
"fmt"
2629

2730
"github.com/pkg/errors"
2831
kerrors "k8s.io/apimachinery/pkg/util/errors"
32+
33+
bootstrapv1 "sigs.k8s.io/cluster-api/api/bootstrap/kubeadm/v1beta2"
2934
)
3035

31-
// NewPrivateKey creates an RSA private key.
32-
func NewPrivateKey() (*rsa.PrivateKey, error) {
33-
pk, err := rsa.GenerateKey(rand.Reader, DefaultRSAKeySize)
36+
// NewPrivateKey creates a private key based on the provided keyAlgorithm.
37+
func NewPrivateKey(keyEncryptionAlgorithm bootstrapv1.EncryptionAlgorithmType) (crypto.Signer, error) {
38+
switch keyEncryptionAlgorithm {
39+
case bootstrapv1.EncryptionAlgorithmECDSAP256:
40+
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
41+
case bootstrapv1.EncryptionAlgorithmECDSAP384:
42+
return ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
43+
}
44+
rsaKeySize := rsaKeySizeFromAlgorithmType(keyEncryptionAlgorithm)
45+
if rsaKeySize == 0 {
46+
return nil, errors.Errorf("cannot obtain key size from unknown RSA algorithm: %q", keyEncryptionAlgorithm)
47+
}
48+
pk, err := rsa.GenerateKey(rand.Reader, rsaKeySize)
3449
return pk, errors.WithStack(err)
3550
}
3651

@@ -44,18 +59,23 @@ func EncodeCertPEM(cert *x509.Certificate) []byte {
4459
}
4560

4661
// EncodePrivateKeyPEM returns PEM-encoded private key data.
47-
func EncodePrivateKeyPEM(key *rsa.PrivateKey) []byte {
62+
func EncodePrivateKeyPEM(key crypto.Signer) ([]byte, error) {
63+
privateBytes, err := x509.MarshalPKCS8PrivateKey(key)
64+
if err != nil {
65+
return nil, fmt.Errorf("unable to marshal private key: %v", err)
66+
}
67+
4868
block := pem.Block{
4969
Type: "RSA PRIVATE KEY",
50-
Bytes: x509.MarshalPKCS1PrivateKey(key),
70+
Bytes: privateBytes,
5171
}
5272

53-
return pem.EncodeToMemory(&block)
73+
return pem.EncodeToMemory(&block), nil
5474
}
5575

5676
// EncodePublicKeyPEM returns PEM-encoded public key data.
57-
func EncodePublicKeyPEM(key *rsa.PublicKey) ([]byte, error) {
58-
der, err := x509.MarshalPKIXPublicKey(key)
77+
func EncodePublicKeyPEM(key crypto.Signer) ([]byte, error) {
78+
der, err := x509.MarshalPKIXPublicKey(key.Public())
5979
if err != nil {
6080
return []byte{}, errors.WithStack(err)
6181
}
@@ -113,3 +133,19 @@ func DecodePrivateKeyPEM(encoded []byte) (crypto.Signer, error) {
113133

114134
return nil, kerrors.NewAggregate(errs)
115135
}
136+
137+
// rsaKeySizeFromAlgorithmType takes a known RSA algorithm defined in the kubeadm API
138+
// and returns its key size. For unknown types it returns 0. For an empty type it returns
139+
// the default size of 2048.
140+
func rsaKeySizeFromAlgorithmType(keyEncryptionAlgorithm bootstrapv1.EncryptionAlgorithmType) int {
141+
switch keyEncryptionAlgorithm {
142+
case bootstrapv1.EncryptionAlgorithmRSA2048, "":
143+
return 2048
144+
case bootstrapv1.EncryptionAlgorithmRSA3072:
145+
return 3072
146+
case bootstrapv1.EncryptionAlgorithmRSA4096:
147+
return 4096
148+
default:
149+
return 0
150+
}
151+
}

util/certs/types.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package certs
1919
import (
2020
"crypto"
2121
"crypto/rand"
22-
"crypto/rsa"
2322
"crypto/x509"
2423
"crypto/x509/pkix"
2524
"math"
@@ -49,7 +48,7 @@ type Config struct {
4948
}
5049

5150
// NewSignedCert creates a signed certificate using the given CA certificate and key.
52-
func (cfg *Config) NewSignedCert(key *rsa.PrivateKey, caCert *x509.Certificate, caKey crypto.Signer) (*x509.Certificate, error) {
51+
func (cfg *Config) NewSignedCert(key crypto.Signer, caCert *x509.Certificate, caKey crypto.Signer) (*x509.Certificate, error) {
5352
serial, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64))
5453
if err != nil {
5554
return nil, errors.Wrap(err, "failed to generate random integer for signed cerficate")

util/kubeconfig/kubeconfig.go

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"k8s.io/client-go/tools/clientcmd/api"
3434
"sigs.k8s.io/controller-runtime/pkg/client"
3535

36+
bootstrapv1 "sigs.k8s.io/cluster-api/api/bootstrap/kubeadm/v1beta2"
3637
clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2"
3738
"sigs.k8s.io/cluster-api/util"
3839
"sigs.k8s.io/cluster-api/util/certs"
@@ -54,14 +55,14 @@ func FromSecret(ctx context.Context, c client.Reader, cluster client.ObjectKey)
5455
}
5556

5657
// New creates a new Kubeconfig using the cluster name and specified endpoint.
57-
func New(clusterName, endpoint string, caCert *x509.Certificate, caKey crypto.Signer) (*api.Config, error) {
58+
func New(clusterName, endpoint string, caCert *x509.Certificate, caKey crypto.Signer, keyEncryptionAlgorithm bootstrapv1.EncryptionAlgorithmType) (*api.Config, error) {
5859
cfg := &certs.Config{
5960
CommonName: "kubernetes-admin",
6061
Organization: []string{"system:masters"},
6162
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
6263
}
6364

64-
clientKey, err := certs.NewPrivateKey()
65+
clientKey, err := certs.NewPrivateKey(keyEncryptionAlgorithm)
6566
if err != nil {
6667
return nil, errors.Wrap(err, "unable to create private key")
6768
}
@@ -74,6 +75,11 @@ func New(clusterName, endpoint string, caCert *x509.Certificate, caKey crypto.Si
7475
userName := fmt.Sprintf("%s-admin", clusterName)
7576
contextName := fmt.Sprintf("%s@%s", userName, clusterName)
7677

78+
encodedClientKey, err := certs.EncodePrivateKeyPEM(clientKey)
79+
if err != nil {
80+
return nil, errors.Wrap(err, "unable to encode private key")
81+
}
82+
7783
return &api.Config{
7884
Clusters: map[string]*api.Cluster{
7985
clusterName: {
@@ -89,7 +95,7 @@ func New(clusterName, endpoint string, caCert *x509.Certificate, caKey crypto.Si
8995
},
9096
AuthInfos: map[string]*api.AuthInfo{
9197
userName: {
92-
ClientKeyData: certs.EncodePrivateKeyPEM(clientKey),
98+
ClientKeyData: encodedClientKey,
9399
ClientCertificateData: certs.EncodeCertPEM(clientCert),
94100
},
95101
},
@@ -98,23 +104,23 @@ func New(clusterName, endpoint string, caCert *x509.Certificate, caKey crypto.Si
98104
}
99105

100106
// CreateSecret creates the Kubeconfig secret for the given cluster.
101-
func CreateSecret(ctx context.Context, c client.Client, cluster *clusterv1.Cluster) error {
107+
func CreateSecret(ctx context.Context, c client.Client, cluster *clusterv1.Cluster, keyEncryptionAlgorithm bootstrapv1.EncryptionAlgorithmType) error {
102108
name := util.ObjectKey(cluster)
103109
return CreateSecretWithOwner(ctx, c, name, cluster.Spec.ControlPlaneEndpoint.String(), metav1.OwnerReference{
104110
APIVersion: clusterv1.GroupVersion.String(),
105111
Kind: "Cluster",
106112
Name: cluster.Name,
107113
UID: cluster.UID,
108-
})
114+
}, keyEncryptionAlgorithm)
109115
}
110116

111117
// CreateSecretWithOwner creates the Kubeconfig secret for the given cluster name, namespace, endpoint, and owner reference.
112-
func CreateSecretWithOwner(ctx context.Context, c client.Client, clusterName client.ObjectKey, endpoint string, owner metav1.OwnerReference) error {
118+
func CreateSecretWithOwner(ctx context.Context, c client.Client, clusterName client.ObjectKey, endpoint string, owner metav1.OwnerReference, keyEncryptionAlgorithm bootstrapv1.EncryptionAlgorithmType) error {
113119
server, err := url.JoinPath("https://", endpoint)
114120
if err != nil {
115121
return err
116122
}
117-
out, err := generateKubeconfig(ctx, c, clusterName, server)
123+
out, err := generateKubeconfig(ctx, c, clusterName, server, keyEncryptionAlgorithm)
118124
if err != nil {
119125
return err
120126
}
@@ -181,7 +187,7 @@ func NeedsClientCertRotation(configSecret *corev1.Secret, threshold time.Duratio
181187
}
182188

183189
// RegenerateSecret creates and stores a new Kubeconfig in the given secret.
184-
func RegenerateSecret(ctx context.Context, c client.Client, configSecret *corev1.Secret) error {
190+
func RegenerateSecret(ctx context.Context, c client.Client, configSecret *corev1.Secret, keyEncryptionAlgorithm bootstrapv1.EncryptionAlgorithmType) error {
185191
clusterName, _, err := secret.ParseSecretName(configSecret.Name)
186192
if err != nil {
187193
return errors.Wrap(err, "failed to parse secret name")
@@ -197,15 +203,15 @@ func RegenerateSecret(ctx context.Context, c client.Client, configSecret *corev1
197203
}
198204
endpoint := config.Clusters[clusterName].Server
199205
key := client.ObjectKey{Name: clusterName, Namespace: configSecret.Namespace}
200-
out, err := generateKubeconfig(ctx, c, key, endpoint)
206+
out, err := generateKubeconfig(ctx, c, key, endpoint, keyEncryptionAlgorithm)
201207
if err != nil {
202208
return err
203209
}
204210
configSecret.Data[secret.KubeconfigDataName] = out
205211
return c.Update(ctx, configSecret)
206212
}
207213

208-
func generateKubeconfig(ctx context.Context, c client.Client, clusterName client.ObjectKey, endpoint string) ([]byte, error) {
214+
func generateKubeconfig(ctx context.Context, c client.Client, clusterName client.ObjectKey, endpoint string, keyEncryptionAlgorithm bootstrapv1.EncryptionAlgorithmType) ([]byte, error) {
209215
clusterCA, err := secret.GetFromNamespacedName(ctx, c, clusterName, secret.ClusterCA)
210216
if err != nil {
211217
if apierrors.IsNotFound(err) {
@@ -228,7 +234,7 @@ func generateKubeconfig(ctx context.Context, c client.Client, clusterName client
228234
return nil, errors.New("CA private key not found")
229235
}
230236

231-
cfg, err := New(clusterName.Name, endpoint, cert, key)
237+
cfg, err := New(clusterName.Name, endpoint, cert, key, keyEncryptionAlgorithm)
232238
if err != nil {
233239
return nil, errors.Wrap(err, "failed to generate a kubeconfig")
234240
}

0 commit comments

Comments
 (0)