diff --git a/cmd/control/tlsconf.go b/cmd/control/tlsconf.go index 736d9c8d..f29769fb 100644 --- a/cmd/control/tlsconf.go +++ b/cmd/control/tlsconf.go @@ -1,110 +1,158 @@ package control import ( - "fmt" + "io/ioutil" "os" "path/filepath" + log "github.com/Sirupsen/logrus" + "github.com/codegangsta/cli" machineUtil "github.com/docker/machine/utils" + "github.com/rancherio/os/config" +) + +const ( + NAME string = "rancher" + BITS int = 2048 ) func tlsConfCommands() []cli.Command { return []cli.Command{ { - Name: "create", - Usage: "use it to create a new set of tls configuration certs and keys or upload existing ones", + Name: "generate", + Usage: "generates new set of TLS configuration certs", Action: tlsConfCreate, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "cakey", - Usage: "path to existing certificate authority key (only use with --generate)", - }, - cli.StringFlag{ - Name: "ca", - Usage: "path to existing certificate authority (only use with --genreate)", + cli.StringSliceFlag{ + Name: "hostname", + Usage: "the hostname for which you want to generate the certificate", + Value: &cli.StringSlice{"localhost"}, }, cli.BoolFlag{ - Name: "generate, g", - Usage: "generate the client key and client cert from existing ca and cakey", + Name: "server, s", + Usage: "generate the server keys instead of client keys", }, cli.StringFlag{ - Name: "outDir, o", - Usage: "the output directory to save the generated certs or keys", + Name: "dir, d", + Usage: "the directory to save/read the certs to/from", + Value: "${HOME}/.docker", }, }, }, } } +func writeCerts(generateServer bool, hostname []string, cfg *config.Config, certPath, keyPath, caCertPath, caKeyPath string) error { + if !generateServer { + return machineUtil.GenerateCert([]string{""}, certPath, keyPath, caCertPath, caKeyPath, NAME, BITS) + } + + if cfg.UserDocker.ServerKey == "" || cfg.UserDocker.ServerCert == "" { + err := machineUtil.GenerateCert(hostname, certPath, keyPath, caCertPath, caKeyPath, NAME, BITS) + if err != nil { + return err + } + + cert, err := ioutil.ReadFile(certPath) + if err != nil { + return err + } + + key, err := ioutil.ReadFile(keyPath) + if err != nil { + return err + } + + return cfg.SetConfig(&config.Config{ + UserDocker: config.DockerConfig{ + CAKey: cfg.UserDocker.CAKey, + CACert: cfg.UserDocker.CACert, + ServerCert: string(cert), + ServerKey: string(key), + }, + }) + } + + if err := ioutil.WriteFile(certPath, []byte(cfg.UserDocker.ServerCert), 0400); err != nil { + return err + } + + return ioutil.WriteFile(keyPath, []byte(cfg.UserDocker.ServerKey), 0400) + +} + +func writeCaCerts(cfg *config.Config, caCertPath, caKeyPath string) error { + if cfg.UserDocker.CACert == "" { + if err := machineUtil.GenerateCACertificate(caCertPath, caKeyPath, NAME, BITS); err != nil { + return err + } + + caCert, err := ioutil.ReadFile(caCertPath) + if err != nil { + return err + } + + caKey, err := ioutil.ReadFile(caKeyPath) + if err != nil { + return err + } + + err = cfg.SetConfig(&config.Config{ + UserDocker: config.DockerConfig{ + CAKey: string(caKey), + CACert: string(caCert), + }, + }) + if err != nil { + return err + } + + return nil + } + + if err := ioutil.WriteFile(caCertPath, []byte(cfg.UserDocker.CACert), 0400); err != nil { + return err + } + + return ioutil.WriteFile(caKeyPath, []byte(cfg.UserDocker.CAKey), 0400) +} + func tlsConfCreate(c *cli.Context) { - name := "rancher" - bits := 2048 - - caCertPath := "ca.pem" - caKeyPath := "ca-key.pem" - outDir := "/etc/docker/tls/" - generateCaCerts := true - - inputCaKey := "" - inputCaCert := "" - - if val := c.String("outDir"); val != "" { - outDir = val - } - - if c.Bool("generate") { - generateCaCerts = false - } - - if val := c.String("cakey"); val != "" { - inputCaKey = val - } - - if val := c.String("ca"); val != "" { - inputCaCert = val - } - - caCertPath = filepath.Join(outDir, caCertPath) - caKeyPath = filepath.Join(outDir, caKeyPath) - - serverCertPath := "server-cert.pem" - serverKeyPath := "server-key.pem" - - if generateCaCerts { - if err := machineUtil.GenerateCACertificate(caCertPath, caKeyPath, name, bits); err != nil { - fmt.Println(err.Error()) - return - } - } else { - if inputCaKey == "" || inputCaCert == "" { - fmt.Println("Please specify caKey and CaCert along with -g") - return - } - - if _, err := os.Stat(inputCaKey); err != nil { - - fmt.Printf("ERROR: %s does not exist\n", inputCaKey) - return - } else { - caKeyPath = inputCaKey - } - - if _, err := os.Stat(inputCaCert); err != nil { - fmt.Printf("ERROR: %s does not exist\n", inputCaCert) - return - } else { - caCertPath = inputCaCert - } - serverCertPath = "client-cert.pem" - serverKeyPath = "client-key.pem" - } - - serverCertPath = filepath.Join(outDir, serverCertPath) - serverKeyPath = filepath.Join(outDir, serverKeyPath) - - if err := machineUtil.GenerateCert([]string{""}, serverCertPath, serverKeyPath, caCertPath, caKeyPath, name, bits); err != nil { - fmt.Println(err.Error()) - return + err := generate(c) + if err != nil { + log.Fatal(err) } } + +func generate(c *cli.Context) error { + cfg, err := config.LoadConfig() + if err != nil { + return err + } + + generateServer := c.Bool("server") + outDir := os.ExpandEnv(c.String("dir")) + caCertPath := filepath.Join(outDir, "ca.pem") + caKeyPath := filepath.Join(outDir, "ca-key.pem") + certPath := filepath.Join(outDir, "cert.pem") + keyPath := filepath.Join(outDir, "key.pem") + + if generateServer { + certPath = filepath.Join(outDir, "server-cert.pem") + keyPath = filepath.Join(outDir, "server-key.pem") + } + + if _, err := os.Stat(outDir); os.IsNotExist(err) { + if err := os.MkdirAll(outDir, 0700); err != nil { + return err + } + } + + if err := writeCaCerts(cfg, caCertPath, caKeyPath); err != nil { + return err + } + + hostnames := c.StringSlice("hostname") + return writeCerts(generateServer, hostnames, cfg, certPath, keyPath, caCertPath, caKeyPath) +}