Skip to content

Commit bccbe19

Browse files
Merge pull request docker-archive-public#2146 from nathanleclaire/rm_automatic_cert_regeneration
Remove automatic certificate regeneration
2 parents f3122dd + f5b6c87 commit bccbe19

File tree

3 files changed

+118
-36
lines changed

3 files changed

+118
-36
lines changed

commands/config.go

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@ import (
1414
"github.com/docker/machine/libmachine/state"
1515
)
1616

17+
// For when the cert is computed to be invalid.
18+
type ErrCertInvalid struct {
19+
wrappedErr error
20+
hostUrl string
21+
}
22+
23+
func (e ErrCertInvalid) Error() string {
24+
return fmt.Sprintf(`There was an error validating certificates for host %q: %s
25+
You can attempt to regenerate them using 'docker-machine regenerate-certs name'.
26+
Be advised that this will trigger a Docker daemon restart which will stop running containers.
27+
`, e.hostUrl, e.wrappedErr)
28+
}
29+
1730
func cmdConfig(c *cli.Context) error {
1831
// Ensure that log messages always go to stderr when this command is
1932
// being run (it is intended to be run in a subshell)
@@ -72,29 +85,19 @@ func runConnectionBoilerplate(h *host.Host, c *cli.Context) (string, *auth.AuthO
7285

7386
authOptions := h.HostOptions.AuthOptions
7487

75-
if err := checkCert(u.Host, authOptions, c); err != nil {
88+
if err := checkCert(u.Host, authOptions); err != nil {
7689
return "", &auth.AuthOptions{}, fmt.Errorf("Error checking and/or regenerating the certs: %s", err)
7790
}
7891

7992
return dockerHost, authOptions, nil
8093
}
8194

82-
func checkCert(hostUrl string, authOptions *auth.AuthOptions, c *cli.Context) error {
83-
valid, err := cert.ValidateCertificate(
84-
hostUrl,
85-
authOptions.CaCertPath,
86-
authOptions.ServerCertPath,
87-
authOptions.ServerKeyPath,
88-
)
89-
if err != nil {
90-
return fmt.Errorf("Error attempting to validate the certificates: %s", err)
91-
}
92-
93-
if !valid {
94-
log.Errorf("Invalid certs detected; regenerating for %s", hostUrl)
95-
96-
if err := runActionWithContext("configureAuth", c); err != nil {
97-
return fmt.Errorf("Error attempting to regenerate the certs: %s", err)
95+
func checkCert(hostUrl string, authOptions *auth.AuthOptions) error {
96+
valid, err := cert.ValidateCertificate(hostUrl, authOptions)
97+
if !valid || err != nil {
98+
return ErrCertInvalid{
99+
wrappedErr: err,
100+
hostUrl: hostUrl,
98101
}
99102
}
100103

commands/config_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package commands
2+
3+
import (
4+
"errors"
5+
"testing"
6+
7+
"github.com/docker/machine/libmachine/auth"
8+
"github.com/docker/machine/libmachine/cert"
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
type FakeValidateCertificate struct {
13+
IsValid bool
14+
Err error
15+
}
16+
17+
type FakeCertGenerator struct {
18+
fakeValidateCertificate *FakeValidateCertificate
19+
}
20+
21+
func (fcg FakeCertGenerator) GenerateCACertificate(certFile, keyFile, org string, bits int) error {
22+
return nil
23+
}
24+
25+
func (fcg FakeCertGenerator) GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org string, bits int) error {
26+
return nil
27+
}
28+
29+
func (fcg FakeCertGenerator) ValidateCertificate(addr string, authOptions *auth.AuthOptions) (bool, error) {
30+
return fcg.fakeValidateCertificate.IsValid, fcg.fakeValidateCertificate.Err
31+
}
32+
33+
func TestCheckCert(t *testing.T) {
34+
errCertsExpired := errors.New("Certs have expired")
35+
36+
cases := []struct {
37+
hostUrl string
38+
authOptions *auth.AuthOptions
39+
valid bool
40+
checkErr error
41+
expectedErr error
42+
}{
43+
{"192.168.99.100:2376", &auth.AuthOptions{}, true, nil, nil},
44+
{"192.168.99.100:2376", &auth.AuthOptions{}, false, nil, ErrCertInvalid{wrappedErr: nil, hostUrl: "192.168.99.100:2376"}},
45+
{"192.168.99.100:2376", &auth.AuthOptions{}, false, errCertsExpired, ErrCertInvalid{wrappedErr: errCertsExpired, hostUrl: "192.168.99.100:2376"}},
46+
}
47+
48+
for _, c := range cases {
49+
fcg := FakeCertGenerator{fakeValidateCertificate: &FakeValidateCertificate{c.valid, c.checkErr}}
50+
cert.SetCertGenerator(fcg)
51+
err := checkCert(c.hostUrl, c.authOptions)
52+
assert.Equal(t, c.expectedErr, err)
53+
}
54+
}

libmachine/cert/cert.go

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"crypto/x509"
88
"crypto/x509/pkix"
99
"encoding/pem"
10-
"fmt"
1110
"io/ioutil"
1211
"math/big"
1312
"net"
@@ -16,18 +15,41 @@ import (
1615

1716
"errors"
1817

18+
"github.com/docker/machine/libmachine/auth"
1919
"github.com/docker/machine/libmachine/log"
2020
)
2121

22-
type ErrValidatingCert struct {
23-
wrappedErr error
22+
var defaultGenerator = NewX509CertGenerator()
23+
24+
type CertGenerator interface {
25+
GenerateCACertificate(certFile, keyFile, org string, bits int) error
26+
GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org string, bits int) error
27+
ValidateCertificate(addr string, authOptions *auth.AuthOptions) (bool, error)
28+
}
29+
30+
type X509CertGenerator struct{}
31+
32+
func NewX509CertGenerator() CertGenerator {
33+
return &X509CertGenerator{}
2434
}
2535

26-
func (e ErrValidatingCert) Error() string {
27-
return fmt.Sprintf("There was an error validating the cert: %s", e.wrappedErr)
36+
func GenerateCACertificate(certFile, keyFile, org string, bits int) error {
37+
return defaultGenerator.GenerateCACertificate(certFile, keyFile, org, bits)
38+
}
39+
40+
func GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org string, bits int) error {
41+
return defaultGenerator.GenerateCert(hosts, certFile, keyFile, caFile, caKeyFile, org, bits)
2842
}
2943

30-
func getTLSConfig(caCert, cert, key []byte, allowInsecure bool) (*tls.Config, error) {
44+
func ValidateCertificate(addr string, authOptions *auth.AuthOptions) (bool, error) {
45+
return defaultGenerator.ValidateCertificate(addr, authOptions)
46+
}
47+
48+
func SetCertGenerator(cg CertGenerator) {
49+
defaultGenerator = cg
50+
}
51+
52+
func (xcg *X509CertGenerator) getTLSConfig(caCert, cert, key []byte, allowInsecure bool) (*tls.Config, error) {
3153
// TLS config
3254
var tlsConfig tls.Config
3355
tlsConfig.InsecureSkipVerify = allowInsecure
@@ -48,7 +70,7 @@ func getTLSConfig(caCert, cert, key []byte, allowInsecure bool) (*tls.Config, er
4870
return &tlsConfig, nil
4971
}
5072

51-
func newCertificate(org string) (*x509.Certificate, error) {
73+
func (xcg *X509CertGenerator) newCertificate(org string) (*x509.Certificate, error) {
5274
now := time.Now()
5375
// need to set notBefore slightly in the past to account for time
5476
// skew in the VMs otherwise the certs sometimes are not yet valid
@@ -78,8 +100,8 @@ func newCertificate(org string) (*x509.Certificate, error) {
78100
// GenerateCACertificate generates a new certificate authority from the specified org
79101
// and bit size and stores the resulting certificate and key file
80102
// in the arguments.
81-
func GenerateCACertificate(certFile, keyFile, org string, bits int) error {
82-
template, err := newCertificate(org)
103+
func (xcg *X509CertGenerator) GenerateCACertificate(certFile, keyFile, org string, bits int) error {
104+
template, err := xcg.newCertificate(org)
83105
if err != nil {
84106
return err
85107
}
@@ -123,8 +145,8 @@ func GenerateCACertificate(certFile, keyFile, org string, bits int) error {
123145
// certificate authority files and stores the result in the certificate
124146
// file and key provided. The provided host names are set to the
125147
// appropriate certificate fields.
126-
func GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org string, bits int) error {
127-
template, err := newCertificate(org)
148+
func (xcg *X509CertGenerator) GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org string, bits int) error {
149+
template, err := xcg.newCertificate(org)
128150
if err != nil {
129151
return err
130152
}
@@ -183,28 +205,32 @@ func GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org stri
183205
}
184206

185207
// ValidateCertificate validate the certificate installed on the vm.
186-
func ValidateCertificate(addr, caCertPath, serverCertPath, serverKeyPath string) (bool, error) {
208+
func (xcg *X509CertGenerator) ValidateCertificate(addr string, authOptions *auth.AuthOptions) (bool, error) {
209+
caCertPath := authOptions.CaCertPath
210+
serverCertPath := authOptions.ServerCertPath
211+
serverKeyPath := authOptions.ServerKeyPath
212+
187213
log.Debugf("Reading CA certificate from %s", caCertPath)
188214
caCert, err := ioutil.ReadFile(caCertPath)
189215
if err != nil {
190-
return false, ErrValidatingCert{err}
216+
return false, err
191217
}
192218

193219
log.Debugf("Reading server certificate from %s", serverCertPath)
194220
serverCert, err := ioutil.ReadFile(serverCertPath)
195221
if err != nil {
196-
return false, ErrValidatingCert{err}
222+
return false, err
197223
}
198224

199225
log.Debugf("Reading server key from %s", serverKeyPath)
200226
serverKey, err := ioutil.ReadFile(serverKeyPath)
201227
if err != nil {
202-
return false, ErrValidatingCert{err}
228+
return false, err
203229
}
204230

205-
tlsConfig, err := getTLSConfig(caCert, serverCert, serverKey, false)
231+
tlsConfig, err := xcg.getTLSConfig(caCert, serverCert, serverKey, false)
206232
if err != nil {
207-
return false, ErrValidatingCert{err}
233+
return false, err
208234
}
209235

210236
dialer := &net.Dialer{
@@ -213,8 +239,7 @@ func ValidateCertificate(addr, caCertPath, serverCertPath, serverKeyPath string)
213239

214240
_, err = tls.DialWithDialer(dialer, "tcp", addr, tlsConfig)
215241
if err != nil {
216-
log.Debugf("Certificates are not valid: %s", err)
217-
return false, nil
242+
return false, err
218243
}
219244

220245
return true, nil

0 commit comments

Comments
 (0)