mirror of https://github.com/docker/docs.git
certs: check if remote is valid and regenerate if not
Signed-off-by: Evan Hazlett <ejhazlett@gmail.com>
This commit is contained in:
parent
89ea1ed4b4
commit
d221d8ee97
114
commands.go
114
commands.go
|
@ -36,8 +36,11 @@ type machineConfig struct {
|
|||
machineName string
|
||||
machineDir string
|
||||
caCertPath string
|
||||
caKeyPath string
|
||||
clientCertPath string
|
||||
clientKeyPath string
|
||||
serverCertPath string
|
||||
serverKeyPath string
|
||||
machineUrl string
|
||||
swarmMaster bool
|
||||
swarmHost string
|
||||
|
@ -68,6 +71,25 @@ func (h hostListItemByName) Less(i, j int) bool {
|
|||
return strings.ToLower(h[i].Name) < strings.ToLower(h[j].Name)
|
||||
}
|
||||
|
||||
func confirmInput(msg string) bool {
|
||||
fmt.Printf("%s (y/n): ", msg)
|
||||
var resp string
|
||||
_, err := fmt.Scanln(&resp)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
||||
}
|
||||
|
||||
if strings.Index(strings.ToLower(resp), "y") == 0 {
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
func setupCertificates(caCertPath, caKeyPath, clientCertPath, clientKeyPath string) error {
|
||||
org := utils.GetUsername()
|
||||
bits := 2048
|
||||
|
@ -207,6 +229,18 @@ var Commands = []cli.Command{
|
|||
Usage: "List machines",
|
||||
Action: cmdLs,
|
||||
},
|
||||
{
|
||||
Name: "regenerate-certs",
|
||||
Usage: "Regenerate TLS Certificates for a machine",
|
||||
Description: "Argument(s) are one or more machine names. Will use the active machine if none is provided.",
|
||||
Action: cmdRegenerateCerts,
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "force, f",
|
||||
Usage: "Force rebuild and do not prompt",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "restart",
|
||||
Usage: "Restart a machine",
|
||||
|
@ -369,6 +403,33 @@ func cmdConfig(c *cli.Context) {
|
|||
|
||||
dockerHost = fmt.Sprintf("tcp://%s:%s", machineIp, swarmPort)
|
||||
}
|
||||
|
||||
u, err := url.Parse(cfg.machineUrl)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if u.Scheme != "unix" {
|
||||
// validate cert and regenerate if needed
|
||||
valid, err := utils.ValidateCertificate(
|
||||
u.Host,
|
||||
cfg.caCertPath,
|
||||
cfg.serverCertPath,
|
||||
cfg.serverKeyPath,
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if !valid {
|
||||
log.Debugf("invalid certs detected; regenerating for %s", u.Host)
|
||||
|
||||
if err := runActionWithContext("configureAuth", c); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("--tlsverify --tlscacert=%s --tlscert=%s --tlskey=%s -H=%s",
|
||||
cfg.caCertPath, cfg.clientCertPath, cfg.clientKeyPath, dockerHost)
|
||||
}
|
||||
|
@ -459,6 +520,16 @@ func cmdLs(c *cli.Context) {
|
|||
w.Flush()
|
||||
}
|
||||
|
||||
func cmdRegenerateCerts(c *cli.Context) {
|
||||
force := c.Bool("force")
|
||||
if force || confirmInput("Regenerate TLS machine certs? Warning: this is irreversible.") {
|
||||
log.Infof("Regenerating TLS certificates")
|
||||
if err := runActionWithContext("configureAuth", c); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cmdRm(c *cli.Context) {
|
||||
if len(c.Args()) == 0 {
|
||||
cli.ShowCommandHelp(c, "rm")
|
||||
|
@ -521,6 +592,32 @@ func cmdEnv(c *cli.Context) {
|
|||
dockerHost = fmt.Sprintf("tcp://%s:%s", machineIp, swarmPort)
|
||||
}
|
||||
|
||||
u, err := url.Parse(cfg.machineUrl)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if u.Scheme != "unix" {
|
||||
// validate cert and regenerate if needed
|
||||
valid, err := utils.ValidateCertificate(
|
||||
u.Host,
|
||||
cfg.caCertPath,
|
||||
cfg.serverCertPath,
|
||||
cfg.serverKeyPath,
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if !valid {
|
||||
log.Debugf("invalid certs detected; regenerating for %s", u.Host)
|
||||
|
||||
if err := runActionWithContext("configureAuth", c); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch userShell {
|
||||
case "fish":
|
||||
fmt.Printf("set -x DOCKER_TLS_VERIFY 1;\nset -x DOCKER_CERT_PATH %s;\nset -x DOCKER_HOST %s;\n",
|
||||
|
@ -574,11 +671,12 @@ func cmdSsh(c *cli.Context) {
|
|||
// We run commands concurrently and communicate back an error if there was one.
|
||||
func machineCommand(actionName string, machine *Host, errorChan chan<- error) {
|
||||
commands := map[string](func() error){
|
||||
"start": machine.Start,
|
||||
"stop": machine.Stop,
|
||||
"restart": machine.Restart,
|
||||
"kill": machine.Kill,
|
||||
"upgrade": machine.Upgrade,
|
||||
"configureAuth": machine.ConfigureAuth,
|
||||
"start": machine.Start,
|
||||
"stop": machine.Stop,
|
||||
"restart": machine.Restart,
|
||||
"kill": machine.Kill,
|
||||
"upgrade": machine.Upgrade,
|
||||
}
|
||||
|
||||
log.Debugf("command=%s machine=%s", actionName, machine.Name)
|
||||
|
@ -811,8 +909,11 @@ func getMachineConfig(c *cli.Context) (*machineConfig, error) {
|
|||
|
||||
machineDir := filepath.Join(utils.GetMachineDir(), machine.Name)
|
||||
caCert := filepath.Join(machineDir, "ca.pem")
|
||||
caKey := filepath.Join(utils.GetMachineCertDir(), "ca-key.pem")
|
||||
clientCert := filepath.Join(machineDir, "cert.pem")
|
||||
clientKey := filepath.Join(machineDir, "key.pem")
|
||||
serverCert := filepath.Join(machineDir, "server.pem")
|
||||
serverKey := filepath.Join(machineDir, "server-key.pem")
|
||||
machineUrl, err := machine.GetURL()
|
||||
if err != nil {
|
||||
if err == drivers.ErrHostIsNotRunning {
|
||||
|
@ -825,8 +926,11 @@ func getMachineConfig(c *cli.Context) (*machineConfig, error) {
|
|||
machineName: name,
|
||||
machineDir: machineDir,
|
||||
caCertPath: caCert,
|
||||
caKeyPath: caKey,
|
||||
clientCertPath: clientCert,
|
||||
clientKeyPath: clientKey,
|
||||
serverCertPath: serverCert,
|
||||
serverKeyPath: serverKey,
|
||||
machineUrl: machineUrl,
|
||||
swarmMaster: machine.SwarmMaster,
|
||||
swarmHost: machine.SwarmHost,
|
||||
|
|
|
@ -460,6 +460,16 @@ foo3 virtualbox Running tcp://192.168.99.108:2376
|
|||
foo4 * virtualbox Running tcp://192.168.99.109:2376
|
||||
```
|
||||
|
||||
#### regenerate-certs
|
||||
|
||||
Regenerate TLS certificates and update the machine with new certs.
|
||||
|
||||
```
|
||||
$ docker-machine regenerate-certs
|
||||
Regenerate TLS machine certs? Warning: this is irreversible. (y/n): y
|
||||
INFO[0013] Regenerating TLS certificates
|
||||
```
|
||||
|
||||
#### restart
|
||||
|
||||
Restart a machine. Oftentimes this is equivalent to
|
||||
|
|
8
host.go
8
host.go
|
@ -245,7 +245,7 @@ func (h *Host) StopDocker() error {
|
|||
|
||||
switch h.Driver.GetProviderType() {
|
||||
case provider.Local:
|
||||
cmd, err = h.GetSSHCommand("if [ -e /var/run/docker.pid ]; then sudo /etc/init.d/docker stop ; fi")
|
||||
cmd, err = h.GetSSHCommand("if [ -e /var/run/docker.pid ] && [ -d /proc/$(cat /var/run/docker.pid) ]; then sudo /etc/init.d/docker stop ; exit 0; fi")
|
||||
case provider.Remote:
|
||||
cmd, err = h.GetSSHCommand("sudo service docker stop")
|
||||
default:
|
||||
|
@ -364,7 +364,7 @@ func (h *Host) ConfigureAuth() error {
|
|||
}
|
||||
machineServerKeyPath := path.Join(dockerDir, "server-key.pem")
|
||||
|
||||
cmd, err = h.GetSSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee -a %s", string(caCert), machineCaCertPath))
|
||||
cmd, err = h.GetSSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee %s", string(caCert), machineCaCertPath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -372,7 +372,7 @@ func (h *Host) ConfigureAuth() error {
|
|||
return err
|
||||
}
|
||||
|
||||
cmd, err = h.GetSSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee -a %s", string(serverKey), machineServerKeyPath))
|
||||
cmd, err = h.GetSSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee %s", string(serverKey), machineServerKeyPath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -380,7 +380,7 @@ func (h *Host) ConfigureAuth() error {
|
|||
return err
|
||||
}
|
||||
|
||||
cmd, err = h.GetSSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee -a %s", string(serverCert), machineServerCertPath))
|
||||
cmd, err = h.GetSSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee %s", string(serverCert), machineServerCertPath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -7,12 +7,33 @@ import (
|
|||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func getTLSConfig(caCert, cert, key []byte, allowInsecure bool) (*tls.Config, error) {
|
||||
// TLS config
|
||||
var tlsConfig tls.Config
|
||||
tlsConfig.InsecureSkipVerify = allowInsecure
|
||||
certPool := x509.NewCertPool()
|
||||
|
||||
certPool.AppendCertsFromPEM(caCert)
|
||||
tlsConfig.RootCAs = certPool
|
||||
keypair, err := tls.X509KeyPair(cert, key)
|
||||
if err != nil {
|
||||
return &tlsConfig, err
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{keypair}
|
||||
if allowInsecure {
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
}
|
||||
|
||||
return &tlsConfig, nil
|
||||
}
|
||||
|
||||
func newCertificate(org string) (*x509.Certificate, error) {
|
||||
now := time.Now()
|
||||
// need to set notBefore slightly in the past to account for time
|
||||
|
@ -149,3 +170,32 @@ func GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org stri
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ValidateCertificate(addr, caCertPath, serverCertPath, serverKeyPath string) (bool, error) {
|
||||
caCert, err := ioutil.ReadFile(caCertPath)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
serverCert, err := ioutil.ReadFile(serverCertPath)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
serverKey, err := ioutil.ReadFile(serverKeyPath)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
tlsConfig, err := getTLSConfig(caCert, serverCert, serverKey, false)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
_, err = tls.Dial("tcp", addr, tlsConfig)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ func TestGenerateCACertificate(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// cleanup
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
os.Setenv("MACHINE_DIR", tmpDir)
|
||||
caCertPath := filepath.Join(tmpDir, "ca.pem")
|
||||
|
@ -29,9 +31,6 @@ func TestGenerateCACertificate(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
os.Setenv("MACHINE_DIR", "")
|
||||
|
||||
// cleanup
|
||||
_ = os.RemoveAll(tmpDir)
|
||||
}
|
||||
|
||||
func TestGenerateCert(t *testing.T) {
|
||||
|
@ -39,6 +38,8 @@ func TestGenerateCert(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// cleanup
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
os.Setenv("MACHINE_DIR", tmpDir)
|
||||
caCertPath := filepath.Join(tmpDir, "ca.pem")
|
||||
|
@ -70,7 +71,4 @@ func TestGenerateCert(t *testing.T) {
|
|||
if _, err := os.Stat(keyPath); err != nil {
|
||||
t.Fatalf("key not created at %s", keyPath)
|
||||
}
|
||||
|
||||
// cleanup
|
||||
_ = os.RemoveAll(tmpDir)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue