@@ -17,8 +17,11 @@ limitations under the License.
17
17
package bootstrapper
18
18
19
19
import (
20
+ "encoding/pem"
20
21
"fmt"
22
+ "io/ioutil"
21
23
"net"
24
+ "os"
22
25
"path"
23
26
"path/filepath"
24
27
"strings"
@@ -36,6 +39,11 @@ import (
36
39
"k8s.io/minikube/pkg/util"
37
40
)
38
41
42
+ const (
43
+ CACertificatesDir = "/usr/share/ca-certificates"
44
+ SSLCertStoreDir = "/etc/ssl/certs"
45
+ )
46
+
39
47
var (
40
48
certs = []string {
41
49
"ca.crt" , "ca.key" , "apiserver.crt" , "apiserver.key" , "proxy-client-ca.crt" ,
@@ -67,6 +75,19 @@ func SetupCerts(cmd command.Runner, k8s config.KubernetesConfig) error {
67
75
copyableFiles = append (copyableFiles , certFile )
68
76
}
69
77
78
+ caCerts , err := collectCACerts ()
79
+ if err != nil {
80
+ return err
81
+ }
82
+ for src , dst := range caCerts {
83
+ certFile , err := assets .NewFileAsset (src , path .Dir (dst ), path .Base (dst ), "0644" )
84
+ if err != nil {
85
+ return err
86
+ }
87
+
88
+ copyableFiles = append (copyableFiles , certFile )
89
+ }
90
+
70
91
kcs := & kubeconfig.Settings {
71
92
ClusterName : k8s .NodeName ,
72
93
ClusterServerAddress : fmt .Sprintf ("https://localhost:%d" , k8s .NodePort ),
@@ -77,7 +98,7 @@ func SetupCerts(cmd command.Runner, k8s config.KubernetesConfig) error {
77
98
}
78
99
79
100
kubeCfg := api .NewConfig ()
80
- err : = kubeconfig .PopulateFromSettings (kcs , kubeCfg )
101
+ err = kubeconfig .PopulateFromSettings (kcs , kubeCfg )
81
102
if err != nil {
82
103
return errors .Wrap (err , "populating kubeconfig" )
83
104
}
@@ -95,6 +116,11 @@ func SetupCerts(cmd command.Runner, k8s config.KubernetesConfig) error {
95
116
return err
96
117
}
97
118
}
119
+
120
+ // configure CA certificates
121
+ if err := configureCACerts (cmd , caCerts ); err != nil {
122
+ return errors .Wrapf (err , "error configuring CA certificates during provisioning %v" , err )
123
+ }
98
124
return nil
99
125
}
100
126
@@ -198,3 +224,122 @@ func generateCerts(k8s config.KubernetesConfig) error {
198
224
199
225
return nil
200
226
}
227
+
228
+ // isValidPEMCertificate checks whether the input file is a valid PEM certificate (with at least one CERTIFICATE block)
229
+ func isValidPEMCertificate (filePath string ) (bool , error ) {
230
+ fileBytes , err := ioutil .ReadFile (filePath )
231
+ if err != nil {
232
+ return false , err
233
+ }
234
+
235
+ for {
236
+ block , rest := pem .Decode (fileBytes )
237
+ if block == nil {
238
+ break
239
+ }
240
+
241
+ if block .Type == "CERTIFICATE" {
242
+ // certificate found
243
+ return true , nil
244
+ }
245
+ fileBytes = rest
246
+ }
247
+
248
+ return false , nil
249
+ }
250
+
251
+ // collectCACerts looks up all PEM certificates with .crt or .pem extension in ~/.minikube/certs to copy to the host.
252
+ // minikube root CA is also included but libmachine certificates (ca.pem/cert.pem) are excluded.
253
+ func collectCACerts () (map [string ]string , error ) {
254
+ localPath := constants .GetMinipath ()
255
+ certFiles := map [string ]string {}
256
+
257
+ certsDir := filepath .Join (localPath , "certs" )
258
+ err := filepath .Walk (certsDir , func (hostpath string , info os.FileInfo , err error ) error {
259
+ if err != nil {
260
+ return err
261
+ }
262
+
263
+ if info != nil && ! info .IsDir () {
264
+ ext := strings .ToLower (filepath .Ext (hostpath ))
265
+ if ext == ".crt" || ext == ".pem" {
266
+ validPem , err := isValidPEMCertificate (hostpath )
267
+ if err != nil {
268
+ return err
269
+ }
270
+ if validPem {
271
+ filename := filepath .Base (hostpath )
272
+ dst := fmt .Sprintf ("%s.%s" , strings .TrimSuffix (filename , ext ), "pem" )
273
+ certFiles [hostpath ] = path .Join (CACertificatesDir , dst )
274
+ }
275
+ }
276
+ }
277
+ return nil
278
+ })
279
+ if err != nil {
280
+ return nil , errors .Wrapf (err , "provisioning: traversal certificates dir %s" , certsDir )
281
+ }
282
+
283
+ for _ , excluded := range []string {"ca.pem" , "cert.pem" } {
284
+ certFiles [filepath .Join (certsDir , excluded )] = ""
285
+ }
286
+
287
+ // populates minikube CA
288
+ certFiles [filepath .Join (localPath , "ca.crt" )] = path .Join (CACertificatesDir , "minikubeCA.pem" )
289
+
290
+ filtered := map [string ]string {}
291
+ for k , v := range certFiles {
292
+ if v != "" {
293
+ filtered [k ] = v
294
+ }
295
+ }
296
+ return filtered , nil
297
+ }
298
+
299
+ // getSubjectHash calculates Certificate Subject Hash for creating certificate symlinks
300
+ func getSubjectHash (cmd command.Runner , filePath string ) (string , error ) {
301
+ out , err := cmd .CombinedOutput (fmt .Sprintf ("openssl x509 -hash -noout -in '%s'" , filePath ))
302
+ if err != nil {
303
+ return "" , err
304
+ }
305
+
306
+ stringHash := strings .TrimSpace (out )
307
+ return stringHash , nil
308
+ }
309
+
310
+ // configureCACerts looks up and installs all uploaded PEM certificates in /usr/share/ca-certificates to system-wide certificate store (/etc/ssl/certs).
311
+ // OpenSSL binary required in minikube ISO
312
+ func configureCACerts (cmd command.Runner , caCerts map [string ]string ) error {
313
+ hasSSLBinary := true
314
+ if err := cmd .Run ("which openssl" ); err != nil {
315
+ hasSSLBinary = false
316
+ }
317
+
318
+ if ! hasSSLBinary && len (caCerts ) > 0 {
319
+ glog .Warning ("OpenSSL not found. Please recreate the cluster with the latest minikube ISO." )
320
+ }
321
+
322
+ for _ , caCertFile := range caCerts {
323
+ dstFilename := path .Base (caCertFile )
324
+ certStorePath := path .Join (SSLCertStoreDir , dstFilename )
325
+ if err := cmd .Run (fmt .Sprintf ("sudo test -f '%s'" , certStorePath )); err != nil {
326
+ if err := cmd .Run (fmt .Sprintf ("sudo ln -s '%s' '%s'" , caCertFile , certStorePath )); err != nil {
327
+ return errors .Wrapf (err , "error making symbol link for certificate %s" , caCertFile )
328
+ }
329
+ }
330
+ if hasSSLBinary {
331
+ subjectHash , err := getSubjectHash (cmd , caCertFile )
332
+ if err != nil {
333
+ return errors .Wrapf (err , "error calculating subject hash for certificate %s" , caCertFile )
334
+ }
335
+ subjectHashLink := path .Join (SSLCertStoreDir , fmt .Sprintf ("%s.0" , subjectHash ))
336
+ if err := cmd .Run (fmt .Sprintf ("sudo test -f '%s'" , subjectHashLink )); err != nil {
337
+ if err := cmd .Run (fmt .Sprintf ("sudo ln -s '%s' '%s'" , certStorePath , subjectHashLink )); err != nil {
338
+ return errors .Wrapf (err , "error making subject hash symbol link for certificate %s" , caCertFile )
339
+ }
340
+ }
341
+ }
342
+ }
343
+
344
+ return nil
345
+ }
0 commit comments