@@ -25,6 +25,7 @@ import (
25
25
"crypto/x509/pkix"
26
26
"encoding/hex"
27
27
"math/big"
28
+ "path/filepath"
28
29
"strings"
29
30
"time"
30
31
@@ -34,6 +35,7 @@ import (
34
35
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35
36
"k8s.io/client-go/util/cert"
36
37
bootstrapv1 "sigs.k8s.io/cluster-api-bootstrap-provider-kubeadm/api/v1alpha2"
38
+ "sigs.k8s.io/cluster-api-bootstrap-provider-kubeadm/kubeadm/v1beta1"
37
39
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha2"
38
40
"sigs.k8s.io/cluster-api/util/certs"
39
41
"sigs.k8s.io/cluster-api/util/secret"
@@ -51,6 +53,11 @@ const (
51
53
52
54
// FrontProxyCA is the secret name suffix for Front Proxy CA
53
55
FrontProxyCA secret.Purpose = "proxy"
56
+
57
+ // APIServerEtcdClient is the secret name of user-supplied secret containing the apiserver-etcd-client key/cert
58
+ APIServerEtcdClient secret.Purpose = "apiserver-etcd-client"
59
+
60
+ defaultCertificatesDir = "/etc/kubernetes/pki"
54
61
)
55
62
56
63
var (
@@ -67,13 +74,65 @@ var (
67
74
// Certificates are the certificates necessary to bootstrap a cluster.
68
75
type Certificates []* Certificate
69
76
70
- // NewCertificates return an initialized but empty set of CA certificates needed to bootstrap a cluster.
71
- func NewCertificates () Certificates {
77
+ // NewCertificatesForControlPlane returns a list of certificates configured for a control plane node
78
+ func NewCertificatesForControlPlane (config * v1beta1.ClusterConfiguration ) Certificates {
79
+ if config .CertificatesDir == "" {
80
+ config .CertificatesDir = defaultCertificatesDir
81
+ }
82
+
83
+ certificates := Certificates {
84
+ & Certificate {
85
+ Purpose : secret .ClusterCA ,
86
+ CertFile : filepath .Join (config .CertificatesDir , "ca.crt" ),
87
+ KeyFile : filepath .Join (config .CertificatesDir , "ca.key" ),
88
+ },
89
+ & Certificate {
90
+ Purpose : ServiceAccount ,
91
+ CertFile : filepath .Join (config .CertificatesDir , "sa.pub" ),
92
+ KeyFile : filepath .Join (config .CertificatesDir , "sa.key" ),
93
+ },
94
+ & Certificate {
95
+ Purpose : FrontProxyCA ,
96
+ CertFile : filepath .Join (config .CertificatesDir , "front-proxy-ca.crt" ),
97
+ KeyFile : filepath .Join (config .CertificatesDir , "front-proxy-ca.key" ),
98
+ },
99
+ }
100
+
101
+ etcdCert := & Certificate {
102
+ Purpose : EtcdCA ,
103
+ CertFile : filepath .Join (config .CertificatesDir , "etcd" , "ca.crt" ),
104
+ KeyFile : filepath .Join (config .CertificatesDir , "etcd" , "ca.key" ),
105
+ }
106
+
107
+ // TODO make sure all the fields are actually defined and return an error if not
108
+ if config .Etcd .External != nil {
109
+ etcdCert = & Certificate {
110
+ Purpose : EtcdCA ,
111
+ CertFile : config .Etcd .External .CAFile ,
112
+ }
113
+ apiserverEtcdClientCert := & Certificate {
114
+ Purpose : APIServerEtcdClient ,
115
+ CertFile : config .Etcd .External .CertFile ,
116
+ KeyFile : config .Etcd .External .KeyFile ,
117
+ }
118
+ certificates = append (certificates , apiserverEtcdClientCert )
119
+ }
120
+
121
+ certificates = append (certificates , etcdCert )
122
+ return certificates
123
+ }
124
+
125
+ // NewCertificatesForWorker return an initialized but empty set of CA certificates needed to bootstrap a cluster.
126
+ func NewCertificatesForWorker (caCertPath string ) Certificates {
127
+ if caCertPath == "" {
128
+ caCertPath = filepath .Join (defaultCertificatesDir , "ca.crt" )
129
+ }
130
+
72
131
return Certificates {
73
- & Certificate {Purpose : secret . ClusterCA },
74
- & Certificate { Purpose : EtcdCA } ,
75
- & Certificate { Purpose : ServiceAccount } ,
76
- & Certificate { Purpose : FrontProxyCA },
132
+ & Certificate {
133
+ Purpose : secret . ClusterCA ,
134
+ CertFile : caCertPath ,
135
+ },
77
136
}
78
137
}
79
138
@@ -138,6 +197,8 @@ func (c Certificates) Generate() error {
138
197
if certificate .KeyPair == nil {
139
198
var generator certGenerator
140
199
switch certificate .Purpose {
200
+ case APIServerEtcdClient : // Do not generate the APIServerEtcdClient key pair. It is user supplied
201
+ continue
141
202
case ServiceAccount :
142
203
generator = generateServiceAccountKeys
143
204
default :
@@ -191,9 +252,10 @@ func (c Certificates) LookupOrGenerate(ctx context.Context, ctrlclient client.Cl
191
252
192
253
// Certificate represents a single certificate CA.
193
254
type Certificate struct {
194
- Generated bool
195
- Purpose secret.Purpose
196
- KeyPair * certs.KeyPair
255
+ Generated bool
256
+ Purpose secret.Purpose
257
+ KeyPair * certs.KeyPair
258
+ CertFile , KeyFile string
197
259
}
198
260
199
261
// Hashes hashes all the certificates stored in a CA certificate.
@@ -244,63 +306,56 @@ func (c *Certificate) AsSecret(cluster *clusterv1.Cluster, config *bootstrapv1.K
244
306
return s
245
307
}
246
308
309
+ // AsFiles converts the certificate to a slice of Files that may have 0, 1 or 2 Files.
310
+ func (c * Certificate ) AsFiles () []bootstrapv1.File {
311
+ out := make ([]bootstrapv1.File , 0 )
312
+ if len (c .KeyPair .Cert ) > 0 {
313
+ out = append (out , bootstrapv1.File {
314
+ Path : c .CertFile ,
315
+ Owner : rootOwnerValue ,
316
+ Permissions : "0640" ,
317
+ Content : string (c .KeyPair .Cert ),
318
+ })
319
+ }
320
+ if len (c .KeyPair .Key ) > 0 {
321
+ out = append (out , bootstrapv1.File {
322
+ Path : c .KeyFile ,
323
+ Owner : rootOwnerValue ,
324
+ Permissions : "0600" ,
325
+ Content : string (c .KeyPair .Key ),
326
+ })
327
+ }
328
+ return out
329
+ }
330
+
247
331
// AsFiles converts a slice of certificates into bootstrap files.
248
332
func (c Certificates ) AsFiles () []bootstrapv1.File {
249
333
clusterCA := c .GetByPurpose (secret .ClusterCA )
250
334
etcdCA := c .GetByPurpose (EtcdCA )
251
335
frontProxyCA := c .GetByPurpose (FrontProxyCA )
252
336
serviceAccountKey := c .GetByPurpose (ServiceAccount )
253
337
254
- return []bootstrapv1.File {
255
- {
256
- Path : "/etc/kubernetes/pki/ca.crt" ,
257
- Owner : rootOwnerValue ,
258
- Permissions : "0640" ,
259
- Content : string (clusterCA .KeyPair .Cert ),
260
- },
261
- {
262
- Path : "/etc/kubernetes/pki/ca.key" ,
263
- Owner : rootOwnerValue ,
264
- Permissions : "0600" ,
265
- Content : string (clusterCA .KeyPair .Key ),
266
- },
267
- {
268
- Path : "/etc/kubernetes/pki/etcd/ca.crt" ,
269
- Owner : rootOwnerValue ,
270
- Permissions : "0640" ,
271
- Content : string (etcdCA .KeyPair .Cert ),
272
- },
273
- {
274
- Path : "/etc/kubernetes/pki/etcd/ca.key" ,
275
- Owner : rootOwnerValue ,
276
- Permissions : "0600" ,
277
- Content : string (etcdCA .KeyPair .Key ),
278
- },
279
- {
280
- Path : "/etc/kubernetes/pki/front-proxy-ca.crt" ,
281
- Owner : rootOwnerValue ,
282
- Permissions : "0640" ,
283
- Content : string (frontProxyCA .KeyPair .Cert ),
284
- },
285
- {
286
- Path : "/etc/kubernetes/pki/front-proxy-ca.key" ,
287
- Owner : rootOwnerValue ,
288
- Permissions : "0600" ,
289
- Content : string (frontProxyCA .KeyPair .Key ),
290
- },
291
- {
292
- Path : "/etc/kubernetes/pki/sa.pub" ,
293
- Owner : rootOwnerValue ,
294
- Permissions : "0640" ,
295
- Content : string (serviceAccountKey .KeyPair .Cert ),
296
- },
297
- {
298
- Path : "/etc/kubernetes/pki/sa.key" ,
299
- Owner : rootOwnerValue ,
300
- Permissions : "0600" ,
301
- Content : string (serviceAccountKey .KeyPair .Key ),
302
- },
338
+ certFiles := make ([]bootstrapv1.File , 0 )
339
+ if clusterCA != nil {
340
+ certFiles = append (certFiles , clusterCA .AsFiles ()... )
341
+ }
342
+ if etcdCA != nil {
343
+ certFiles = append (certFiles , etcdCA .AsFiles ()... )
344
+ }
345
+ if frontProxyCA != nil {
346
+ certFiles = append (certFiles , frontProxyCA .AsFiles ()... )
347
+ }
348
+ if serviceAccountKey != nil {
349
+ certFiles = append (certFiles , serviceAccountKey .AsFiles ()... )
303
350
}
351
+
352
+ // these will only exist if external etcd was defined and supplied by the user
353
+ apiserverEtcdClientCert := c .GetByPurpose (APIServerEtcdClient )
354
+ if apiserverEtcdClientCert != nil {
355
+ certFiles = append (certFiles , apiserverEtcdClientCert .AsFiles ()... )
356
+ }
357
+
358
+ return certFiles
304
359
}
305
360
306
361
func secretToKeyPair (s * corev1.Secret ) (* certs.KeyPair , error ) {
@@ -309,9 +364,11 @@ func secretToKeyPair(s *corev1.Secret) (*certs.KeyPair, error) {
309
364
return nil , errors .Errorf ("missing data for key %s" , secret .TLSCrtDataName )
310
365
}
311
366
367
+ // In some cases (external etcd) it's ok if the etcd.key does not exist.
368
+ // TODO: some other function should ensure that the certificates we need exist.
312
369
key , exists := s .Data [secret .TLSKeyDataName ]
313
370
if ! exists {
314
- return nil , errors . Errorf ( "missing data for key %s" , secret . TLSKeyDataName )
371
+ key = [] byte ( "" )
315
372
}
316
373
317
374
return & certs.KeyPair {
0 commit comments