1
+ /*
2
+ Copyright 2019 The Kubernetes Authors.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
1
17
package internal
2
18
3
19
import (
@@ -8,10 +24,8 @@ import (
8
24
"crypto/x509"
9
25
"crypto/x509/pkix"
10
26
"encoding/hex"
11
- "encoding/pem"
12
27
"fmt"
13
28
"math/big"
14
- "net"
15
29
"strings"
16
30
"time"
17
31
@@ -22,14 +36,17 @@ import (
22
36
"k8s.io/client-go/util/cert"
23
37
bootstrapv1 "sigs.k8s.io/cluster-api-bootstrap-provider-kubeadm/api/v1alpha2"
24
38
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha2"
39
+ "sigs.k8s.io/cluster-api/util/certs"
25
40
"sigs.k8s.io/controller-runtime/pkg/client"
26
41
)
27
42
28
43
const (
29
- rsaKeySize = 2048
30
44
rootOwnerValue = "root:root"
31
45
46
+ // TLSKeyDataName is the name of the secret key within the certificate secret of the key
32
47
TLSKeyDataName = "tls.key"
48
+
49
+ // TLSCrtDataName is the name of the secret key within the certificate secret of the certificate
33
50
TLSCrtDataName = "tls.crt"
34
51
35
52
// ClusterCAName is the secret name suffix for apiserver CA
@@ -45,8 +62,10 @@ const (
45
62
FrontProxyCAName = "proxy"
46
63
)
47
64
65
+ // Certificates are the certificates necessary to bootstrap a cluster.
48
66
type Certificates []* Certificate
49
67
68
+ // NewCertificates return an initialized but empty set of CA certificates needed to bootstrap a cluster.
50
69
func NewCertificates () Certificates {
51
70
return Certificates {
52
71
& Certificate {Name : ClusterCAName },
@@ -56,6 +75,8 @@ func NewCertificates() Certificates {
56
75
}
57
76
}
58
77
78
+ // GetCertificateByName returns a certificate by the given name.
79
+ // This could be removed if we use a map instead of a slice to hold certificates, however other code becomes more complex.
59
80
func (c Certificates ) GetCertificateByName (name string ) * Certificate {
60
81
for _ , certificate := range c {
61
82
if certificate .Name == name {
@@ -65,6 +86,7 @@ func (c Certificates) GetCertificateByName(name string) *Certificate {
65
86
return nil
66
87
}
67
88
89
+ // GetCertificates looks up each certificate from secrets and populates the certificate with the secret data.
68
90
func (c Certificates ) GetCertificates (ctx context.Context , ctrlclient client.Client , cluster * clusterv1.Cluster ) error {
69
91
// Look up each certificate as a secret and populate the certificate/key
70
92
for _ , certificate := range c {
@@ -95,6 +117,7 @@ func (c Certificates) GetCertificates(ctx context.Context, ctrlclient client.Cli
95
117
return nil
96
118
}
97
119
120
+ // GenerateCertificates will generate any certificates that do not have KeyPair data.
98
121
func (c Certificates ) GenerateCertificates () error {
99
122
for _ , certificate := range c {
100
123
if certificate .KeyPair == nil {
@@ -109,6 +132,7 @@ func (c Certificates) GenerateCertificates() error {
109
132
return nil
110
133
}
111
134
135
+ // SaveGeneratedCertificates will save any certificates that have been generated as Kubernetes secrets.
112
136
func (c Certificates ) SaveGeneratedCertificates (ctx context.Context , ctrlclient client.Client , cluster * clusterv1.Cluster , config * bootstrapv1.KubeadmConfig ) error {
113
137
for _ , certificate := range c {
114
138
if ! certificate .Generated {
@@ -122,6 +146,7 @@ func (c Certificates) SaveGeneratedCertificates(ctx context.Context, ctrlclient
122
146
return nil
123
147
}
124
148
149
+ // GetOrCreateCertificates is a convenience function that wraps cluster bootstrap certificate behavior.
125
150
func (c Certificates ) GetOrCreateCertificates (ctx context.Context , ctrlclient client.Client , cluster * clusterv1.Cluster , config * bootstrapv1.KubeadmConfig ) error {
126
151
// Get the certificates that exist
127
152
if err := c .GetCertificates (ctx , ctrlclient , cluster ); err != nil {
@@ -141,17 +166,19 @@ func (c Certificates) GetOrCreateCertificates(ctx context.Context, ctrlclient cl
141
166
return nil
142
167
}
143
168
169
+ // Certificate represents a single certificate CA.
144
170
type Certificate struct {
145
171
Generated bool
146
172
Name string
147
- * KeyPair
173
+ * certs. KeyPair
148
174
}
149
175
176
+ // SecretName is the expected name of the Kubernetes secret the certificate is saved in.
150
177
func (c * Certificate ) SecretName (clustername string ) string {
151
178
return fmt .Sprintf ("%s-%s" , clustername , c .Name )
152
179
}
153
180
154
- // CertificateHashes hash all the certificates stored in a CA certificate.
181
+ // Hashes hash all the certificates stored in a CA certificate.
155
182
func (c * Certificate ) Hashes () ([]string , error ) {
156
183
certificates , err := cert .ParseCertsPEM (c .Cert )
157
184
if err != nil {
@@ -164,17 +191,13 @@ func (c *Certificate) Hashes() ([]string, error) {
164
191
return out , nil
165
192
}
166
193
167
- // HashCert will calculate the sha256 of the incoming certificate.
194
+ // hashCert will calculate the sha256 of the incoming certificate.
168
195
func hashCert (certificate * x509.Certificate ) string {
169
196
spkiHash := sha256 .Sum256 (certificate .RawSubjectPublicKeyInfo )
170
197
return "sha256:" + strings .ToLower (hex .EncodeToString (spkiHash [:]))
171
198
}
172
199
173
- // KeyPair holds the raw bytes for a certificate and key
174
- type KeyPair struct {
175
- Cert , Key []byte
176
- }
177
-
200
+ // AsSecret will convert a single certificate into a Kubernetes secret.
178
201
func (c * Certificate ) AsSecret (cluster * clusterv1.Cluster , config * bootstrapv1.KubeadmConfig ) * corev1.Secret {
179
202
secret := & corev1.Secret {
180
203
ObjectMeta : metav1.ObjectMeta {
@@ -203,6 +226,7 @@ func (c *Certificate) AsSecret(cluster *clusterv1.Cluster, config *bootstrapv1.K
203
226
return secret
204
227
}
205
228
229
+ // AsFiles converts a slice of certificates into bootstrap files.
206
230
func (c Certificates ) AsFiles () []bootstrapv1.File {
207
231
clusterCA := c .GetCertificateByName (ClusterCAName )
208
232
etcdCA := c .GetCertificateByName (EtcdCAName )
@@ -264,19 +288,15 @@ func (c Certificates) AsFiles() []bootstrapv1.File {
264
288
// Validate checks that all KeyPairs are valid
265
289
func (c Certificates ) Validate () error {
266
290
for _ , certificate := range c {
267
- if ! certificate .KeyPair .isValid () {
291
+ if ! certificate .KeyPair .IsValid () {
268
292
return errors .Errorf ("CA cert material is missing cert/key for %s" , certificate .Name )
269
293
}
270
294
}
271
295
return nil
272
296
}
273
297
274
- func (kp * KeyPair ) isValid () bool {
275
- return kp .Cert != nil && kp .Key != nil
276
- }
277
-
278
- func secretToKeyPair (s * corev1.Secret ) (* KeyPair , error ) {
279
- cert , exists := s .Data [TLSCrtDataName ]
298
+ func secretToKeyPair (s * corev1.Secret ) (* certs.KeyPair , error ) {
299
+ c , exists := s .Data [TLSCrtDataName ]
280
300
if ! exists {
281
301
return nil , errors .Errorf ("missing data for key %s" , TLSCrtDataName )
282
302
}
@@ -286,47 +306,41 @@ func secretToKeyPair(s *corev1.Secret) (*KeyPair, error) {
286
306
return nil , errors .Errorf ("missing data for key %s" , TLSKeyDataName )
287
307
}
288
308
289
- return & KeyPair {
290
- Cert : cert ,
309
+ return & certs. KeyPair {
310
+ Cert : c ,
291
311
Key : key ,
292
312
}, nil
293
313
}
294
314
295
- func generateCACert () (* KeyPair , error ) {
315
+ func generateCACert () (* certs. KeyPair , error ) {
296
316
x509Cert , privKey , err := newCertificateAuthority ()
297
317
if err != nil {
298
318
return nil , err
299
319
}
300
- return & KeyPair {
301
- Cert : encodeCertPEM (x509Cert ),
302
- Key : encodePrivateKeyPEM (privKey ),
320
+ return & certs. KeyPair {
321
+ Cert : certs . EncodeCertPEM (x509Cert ),
322
+ Key : certs . EncodePrivateKeyPEM (privKey ),
303
323
}, nil
304
324
}
305
325
306
326
// newCertificateAuthority creates new certificate and private key for the certificate authority
307
327
func newCertificateAuthority () (* x509.Certificate , * rsa.PrivateKey , error ) {
308
- key , err := newPrivateKey ()
328
+ key , err := certs . NewPrivateKey ()
309
329
if err != nil {
310
330
return nil , nil , err
311
331
}
312
332
313
- cert , err := newSelfSignedCACert (key )
333
+ c , err := newSelfSignedCACert (key )
314
334
if err != nil {
315
335
return nil , nil , err
316
336
}
317
337
318
- return cert , key , nil
319
- }
320
-
321
- // newPrivateKey creates an RSA private key
322
- func newPrivateKey () (* rsa.PrivateKey , error ) {
323
- pk , err := rsa .GenerateKey (rand .Reader , rsaKeySize )
324
- return pk , errors .WithStack (err )
338
+ return c , key , nil
325
339
}
326
340
327
341
// newSelfSignedCACert creates a CA certificate.
328
342
func newSelfSignedCACert (key * rsa.PrivateKey ) (* x509.Certificate , error ) {
329
- cfg := config {
343
+ cfg := certs. Config {
330
344
CommonName : "kubernetes" ,
331
345
}
332
346
@@ -352,41 +366,6 @@ func newSelfSignedCACert(key *rsa.PrivateKey) (*x509.Certificate, error) {
352
366
return nil , errors .Wrapf (err , "failed to create self signed CA certificate: %+v" , tmpl )
353
367
}
354
368
355
- cert , err := x509 .ParseCertificate (b )
356
- return cert , errors .WithStack (err )
357
- }
358
-
359
- // encodeCertPEM returns PEM-endcoded certificate data.
360
- func encodeCertPEM (cert * x509.Certificate ) []byte {
361
- block := pem.Block {
362
- Type : "CERTIFICATE" ,
363
- Bytes : cert .Raw ,
364
- }
365
- return pem .EncodeToMemory (& block )
366
- }
367
-
368
- // encodePrivateKeyPEM returns PEM-encoded private key data.
369
- func encodePrivateKeyPEM (key * rsa.PrivateKey ) []byte {
370
- block := pem.Block {
371
- Type : "RSA PRIVATE KEY" ,
372
- Bytes : x509 .MarshalPKCS1PrivateKey (key ),
373
- }
374
-
375
- return pem .EncodeToMemory (& block )
376
- }
377
-
378
- // config contains the basic fields required for creating a certificate
379
- type config struct {
380
- CommonName string
381
- Organization []string
382
- AltNames altNames
383
- Usages []x509.ExtKeyUsage
384
- }
385
-
386
- // AltNames contains the domain names and IP addresses that will be added
387
- // to the API Server's x509 certificate SubAltNames field. The values will
388
- // be passed directly to the x509.Certificate object.
389
- type altNames struct {
390
- DNSNames []string
391
- IPs []net.IP
369
+ c , err := x509 .ParseCertificate (b )
370
+ return c , errors .WithStack (err )
392
371
}
0 commit comments