From 74f9bcebc78d0b4924a2ed4680c5a2625b0780b9 Mon Sep 17 00:00:00 2001 From: Evan Hazlett Date: Fri, 23 Jan 2015 21:27:29 -0500 Subject: [PATCH] only create ca and client cert once; create server keys each time; add serverAuth to ext usage Signed-off-by: Evan Hazlett --- commands.go | 10 ++--- drivers/utils.go | 16 ++----- drivers/virtualbox/virtualbox.go | 2 +- drivers/vmwarefusion/fusion.go | 2 +- drivers/vmwarevsphere/vsphere.go | 3 +- host.go | 76 +++++++++----------------------- main.go | 63 ++++++++++++++++++++++++-- store.go | 3 +- utils/certs.go | 4 +- utils/utils.go | 18 ++++++++ 10 files changed, 113 insertions(+), 84 deletions(-) diff --git a/commands.go b/commands.go index e6e5319d96..706fcfb183 100644 --- a/commands.go +++ b/commands.go @@ -27,6 +27,7 @@ import ( _ "github.com/docker/machine/drivers/vmwarevcloudair" _ "github.com/docker/machine/drivers/vmwarevsphere" "github.com/docker/machine/state" + "github.com/docker/machine/utils" ) type hostListItem struct { @@ -156,7 +157,7 @@ var Commands = []cli.Command{ func cmdActive(c *cli.Context) { name := c.Args().First() - store := NewStore(c.GlobalString("storage-path"), c.GlobalString("auth-ca"), c.GlobalString("auth-key")) + store := NewStore(c.GlobalString("storage-path"), c.GlobalString("tls-ca-cert"), c.GlobalString("tls-ca-key")) if name == "" { host, err := store.GetActive() @@ -221,10 +222,9 @@ func cmdConfig(c *cli.Context) { log.Fatalf("Error loading machine config: %s", err) } - storeDir := store.Path - caCert := filepath.Join(storeDir, name, "ca.pem") - clientCert := filepath.Join(storeDir, name, "cert.pem") - clientKey := filepath.Join(storeDir, name, "key.pem") + caCert := filepath.Join(utils.GetMachineDir(), "ca.pem") + clientCert := filepath.Join(utils.GetMachineDir(), "client.pem") + clientKey := filepath.Join(utils.GetMachineDir(), "client-key.pem") machineUrl, err := host.GetURL() if err != nil { log.Fatalf("Error getting machine url: %s", err) diff --git a/drivers/utils.go b/drivers/utils.go index bda7dbd775..eed87885a8 100644 --- a/drivers/utils.go +++ b/drivers/utils.go @@ -4,22 +4,12 @@ import ( "fmt" "os" "path/filepath" - "runtime" + + "github.com/docker/machine/utils" ) -func GetHomeDir() string { - if runtime.GOOS == "windows" { - return os.Getenv("USERPROFILE") - } - return os.Getenv("HOME") -} - -func GetDockerDir() string { - return fmt.Sprintf(filepath.Join(GetHomeDir(), ".docker")) -} - func PublicKeyPath() string { - return filepath.Join(GetHomeDir(), ".docker", "public-key.json") + return filepath.Join(utils.GetHomeDir(), ".docker", "public-key.json") } func AddPublicKeyToAuthorizedHosts(d Driver, authorizedKeysPath string) error { diff --git a/drivers/virtualbox/virtualbox.go b/drivers/virtualbox/virtualbox.go index 7a4cdb8b41..be97113757 100644 --- a/drivers/virtualbox/virtualbox.go +++ b/drivers/virtualbox/virtualbox.go @@ -143,7 +143,7 @@ func (d *Driver) Create() error { } // todo: use real constant for .docker - rootPath := filepath.Join(drivers.GetHomeDir(), ".docker") + rootPath := filepath.Join(utils.GetHomeDir(), ".docker") imgPath := filepath.Join(rootPath, "images") commonIsoPath := filepath.Join(imgPath, "boot2docker.iso") if _, err := os.Stat(commonIsoPath); os.IsNotExist(err) { diff --git a/drivers/vmwarefusion/fusion.go b/drivers/vmwarefusion/fusion.go index 775e0515e4..28e6ef02a7 100644 --- a/drivers/vmwarefusion/fusion.go +++ b/drivers/vmwarefusion/fusion.go @@ -151,7 +151,7 @@ func (d *Driver) Create() error { } // todo: use real constant for .docker - rootPath := filepath.Join(drivers.GetHomeDir(), ".docker") + rootPath := filepath.Join(utils.GetHomeDir(), ".docker") imgPath := filepath.Join(rootPath, "images") commonIsoPath := filepath.Join(imgPath, "boot2docker.iso") if _, err := os.Stat(commonIsoPath); os.IsNotExist(err) { diff --git a/drivers/vmwarevsphere/vsphere.go b/drivers/vmwarevsphere/vsphere.go index 5b003d8dda..ecb4456610 100644 --- a/drivers/vmwarevsphere/vsphere.go +++ b/drivers/vmwarevsphere/vsphere.go @@ -244,8 +244,7 @@ func (d *Driver) Create() error { return err } - // todo: use real constant for .docker - rootPath := filepath.Join(drivers.GetHomeDir(), ".docker") + rootPath := utils.GetDockerDir() imgPath := filepath.Join(rootPath, "images") commonIsoPath := filepath.Join(imgPath, "boot2docker.iso") if _, err := os.Stat(commonIsoPath); os.IsNotExist(err) { diff --git a/host.go b/host.go index 61f4145c9c..17960f1b94 100644 --- a/host.go +++ b/host.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "net" "os" + "path" "path/filepath" "regexp" "time" @@ -83,59 +84,15 @@ func ValidateHostName(name string) (string, error) { return name, nil } -func (h *Host) GenerateCertificates() error { +func GenerateClientCertificate(caCertPath, privateKeyPath string) error { var ( - caPathExists bool - privateKeyExists bool - org = "docker-machine" - bits = 2048 + org = "docker-machine" + bits = 2048 ) - ip, err := h.Driver.GetIP() - if err != nil { - return err - } + clientCertPath := filepath.Join(utils.GetMachineDir(), "cert.pem") + clientKeyPath := filepath.Join(utils.GetMachineDir(), "key.pem") - caCertPath := filepath.Join(h.storePath, "ca.pem") - privateKeyPath := filepath.Join(h.storePath, "private.pem") - - if _, err := os.Stat(h.CaCertPath); os.IsNotExist(err) { - caPathExists = false - } else { - caPathExists = true - } - - if _, err := os.Stat(h.PrivateKeyPath); os.IsNotExist(err) { - privateKeyExists = false - } else { - privateKeyExists = true - } - - if !caPathExists && !privateKeyExists { - log.Debugf("generating self-signed CA cert: %s", caCertPath) - if err := utils.GenerateCACert(caCertPath, privateKeyPath, org, bits); err != nil { - return fmt.Errorf("error generating self-signed CA cert: %s", err) - } - } else { - if err := utils.CopyFile(h.CaCertPath, caCertPath); err != nil { - return fmt.Errorf("unable to copy CA cert: %s", err) - } - if err := utils.CopyFile(h.PrivateKeyPath, privateKeyPath); err != nil { - return fmt.Errorf("unable to copy private key: %s", err) - } - } - - serverCertPath := filepath.Join(h.storePath, "server.pem") - serverKeyPath := filepath.Join(h.storePath, "server-key.pem") - - log.Debugf("generating server cert: %s", serverCertPath) - - if err := utils.GenerateCert([]string{ip}, serverCertPath, serverKeyPath, caCertPath, privateKeyPath, org, bits); err != nil { - return fmt.Errorf("error generating server cert: %s", err) - } - - clientCertPath := filepath.Join(h.storePath, "cert.pem") - clientKeyPath := filepath.Join(h.storePath, "key.pem") log.Debugf("generating client cert: %s", clientCertPath) if err := utils.GenerateCert([]string{""}, clientCertPath, clientKeyPath, caCertPath, privateKeyPath, org, bits); err != nil { return fmt.Errorf("error generating client cert: %s", err) @@ -151,14 +108,23 @@ func (h *Host) ConfigureAuth() error { return nil } - log.Debugf("generating certificates for %s", h.Name) - if err := h.GenerateCertificates(); err != nil { + ip, err := h.Driver.GetIP() + if err != nil { return err } + caCertPath := filepath.Join(utils.GetMachineDir(), "ca.pem") + caKeyPath := filepath.Join(utils.GetMachineDir(), "key.pem") serverCertPath := filepath.Join(h.storePath, "server.pem") - caCertPath := filepath.Join(h.storePath, "ca.pem") serverKeyPath := filepath.Join(h.storePath, "server-key.pem") + org := "docker" + bits := 2048 + + log.Debugf("generating server cert: %s", serverCertPath) + + if err := utils.GenerateCert([]string{ip}, serverCertPath, serverKeyPath, caCertPath, caKeyPath, org, bits); err != nil { + return fmt.Errorf("error generating server cert: %s", err) + } if err := d.StopDocker(); err != nil { return err @@ -180,19 +146,19 @@ func (h *Host) ConfigureAuth() error { // due to windows clients, we cannot use filepath.Join as the paths // will be mucked on the linux hosts - machineCaCertPath := fmt.Sprintf("%s/ca.pem", d.GetDockerConfigDir()) + machineCaCertPath := path.Join(d.GetDockerConfigDir(), "ca.pem") serverCert, err := ioutil.ReadFile(serverCertPath) if err != nil { return err } - machineServerCertPath := fmt.Sprintf("%s/server.pem", d.GetDockerConfigDir()) + machineServerCertPath := path.Join(d.GetDockerConfigDir(), "server.pem") serverKey, err := ioutil.ReadFile(serverKeyPath) if err != nil { return err } - machineServerKeyPath := fmt.Sprintf("%s/server-key.pem", d.GetDockerConfigDir()) + machineServerKeyPath := path.Join(d.GetDockerConfigDir(), "server-key.pem") cmd, err = d.GetSSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee -a %s", string(caCert), machineCaCertPath)) if err != nil { diff --git a/main.go b/main.go index 1093258fb9..c6abc9b533 100644 --- a/main.go +++ b/main.go @@ -3,11 +3,51 @@ package main import ( "os" "path" + "path/filepath" log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" + "github.com/docker/machine/utils" ) +func before(c *cli.Context) error { + + caCertPath := c.GlobalString("tls-ca-cert") + caKeyPath := c.GlobalString("tls-ca-key") + clientCertPath := c.GlobalString("tls-client-cert") + clientKeyPath := c.GlobalString("tls-client-key") + org := "docker" + bits := 2048 + + if _, err := os.Stat(caCertPath); os.IsNotExist(err) { + log.Debugf("Creating CA: %s", caCertPath) + + // check if the key path exists; if so, error + if _, err := os.Stat(caKeyPath); err == nil { + log.Fatalf("The CA key already exists. Please remove it or specify a different key/cert.") + } + + if err := utils.GenerateCACertificate(caCertPath, caKeyPath, org, bits); err != nil { + log.Fatalf("Error generating CA certificate: %s", err) + } + } + + if _, err := os.Stat(clientCertPath); os.IsNotExist(err) { + log.Debugf("Creating client certificate: %s", clientCertPath) + + // check if the key path exists; if so, error + if _, err := os.Stat(clientKeyPath); err == nil { + log.Fatalf("The client key already exists. Please remove it or specify a different key/cert.") + } + + if err := utils.GenerateCert([]string{""}, clientCertPath, clientKeyPath, caCertPath, caKeyPath, org, bits); err != nil { + log.Fatalf("Error generating client certificate: %s", err) + } + } + + return nil +} + func main() { for _, f := range os.Args { if f == "-D" || f == "--debug" || f == "-debug" { @@ -21,6 +61,7 @@ func main() { app.Commands = Commands app.CommandNotFound = cmdNotFound app.Usage = "Create and manage machines running Docker." + app.Before = before app.Version = VERSION app.Flags = []cli.Flag{ @@ -34,14 +75,28 @@ func main() { Usage: "Configures storage path", }, cli.StringFlag{ - EnvVar: "MACHINE_AUTH_CA", - Name: "auth-ca", + EnvVar: "MACHINE_TLS_CA_CERT", + Name: "tls-ca-cert", Usage: "CA to verify remotes against", + Value: filepath.Join(utils.GetMachineDir(), "ca.pem"), }, cli.StringFlag{ - EnvVar: "MACHINE_AUTH_PRIVATE_KEY", - Name: "auth-key", + EnvVar: "MACHINE_TLS_CA_KEY", + Name: "tls-ca-key", Usage: "Private key to generate certificates", + Value: filepath.Join(utils.GetMachineDir(), "key.pem"), + }, + cli.StringFlag{ + EnvVar: "MACHINE_TLS_CLIENT_CERT", + Name: "tls-client-cert", + Usage: "Client cert to use for TLS", + Value: filepath.Join(utils.GetMachineDir(), "client.pem"), + }, + cli.StringFlag{ + EnvVar: "MACHINE_TLS_CLIENT_KEY", + Name: "tls-client-key", + Usage: "Private key used in client TLS auth", + Value: filepath.Join(utils.GetMachineDir(), "client-key.pem"), }, } diff --git a/store.go b/store.go index 61a4025977..c7a46d891e 100644 --- a/store.go +++ b/store.go @@ -8,6 +8,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/docker/machine/drivers" + "github.com/docker/machine/utils" ) // Store persists hosts on the filesystem @@ -19,7 +20,7 @@ type Store struct { func NewStore(rootPath string, caCert string, privateKey string) *Store { if rootPath == "" { - rootPath = filepath.Join(drivers.GetHomeDir(), ".docker", "machines") + rootPath = utils.GetMachineDir() } return &Store{Path: rootPath, CaCertPath: caCert, PrivateKeyPath: privateKey} diff --git a/utils/certs.go b/utils/certs.go index 4b89a67d59..70b8a6cde9 100644 --- a/utils/certs.go +++ b/utils/certs.go @@ -40,10 +40,10 @@ func newCertificate(org string) (*x509.Certificate, error) { } -// GenerateCACert generates a new certificate authority from the specified org +// GenerateCACertificate generates a new certificate authority from the specified org // and bit size and stores the resulting certificate and key file // in the arguments. -func GenerateCACert(certFile, keyFile, org string, bits int) error { +func GenerateCACertificate(certFile, keyFile, org string, bits int) error { template, err := newCertificate(org) if err != nil { return err diff --git a/utils/utils.go b/utils/utils.go index 88809b56bd..41b4f29030 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -1,10 +1,28 @@ package utils import ( + "fmt" "io" "os" + "path/filepath" + "runtime" ) +func GetHomeDir() string { + if runtime.GOOS == "windows" { + return os.Getenv("USERPROFILE") + } + return os.Getenv("HOME") +} + +func GetDockerDir() string { + return fmt.Sprintf(filepath.Join(GetHomeDir(), ".docker")) +} + +func GetMachineDir() string { + return fmt.Sprintf(filepath.Join(GetDockerDir(), "machines")) +} + func CopyFile(src, dst string) error { in, err := os.Open(src) if err != nil {