diff --git a/.gitignore b/.gitignore index 611e303644..f7fa371f4f 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,6 @@ _testmain.go # Other dirs bin/ pkg/ + +# Vault-specific +example.hcl diff --git a/command/init.go b/command/init.go new file mode 100644 index 0000000000..7b3813e299 --- /dev/null +++ b/command/init.go @@ -0,0 +1,90 @@ +package command + +import ( + "fmt" + "strings" + + "github.com/hashicorp/vault/api" +) + +// InitCommand is a Command that initializes a new Vault server. +type InitCommand struct { + Meta +} + +func (c *InitCommand) Run(args []string) int { + var shares, threshold int + flags := c.Meta.FlagSet("init", FlagSetDefault) + flags.Usage = func() { c.Ui.Error(c.Help()) } + flags.IntVar(&shares, "key-shares", 5, "") + flags.IntVar(&threshold, "key-threshold", 3, "") + if err := flags.Parse(args); err != nil { + return 1 + } + + client, err := c.Client() + if err != nil { + c.Ui.Error(fmt.Sprintf( + "Error initializing client: %s", err)) + return 1 + } + + resp, err := client.Sys().Init(&api.InitRequest{ + SecretShares: shares, + SecretThreshold: threshold, + }) + if err != nil { + c.Ui.Error(fmt.Sprintf( + "Error initializing Vault: %s", err)) + return 1 + } + + for _, key := range resp.Keys { + c.Ui.Output(fmt.Sprintf("Key: %s", key)) + } + + return 0 +} + +func (c *InitCommand) Synopsis() string { + return "Initialize a new Vault server" +} + +func (c *InitCommand) Help() string { + helpText := ` +Usage: vault init [options] + + Initialize a new Vault server. + + This command connects to a Vault server and initializes it for the + first time. This sets up the initial set of master keys and sets up the + backend data store structure. + + This command can't be called on an already-initialized Vault. + +General Options: + + -address=TODO The address of the Vault server. + + -ca-cert=path Path to a PEM encoded CA cert file to use to + verify the Vault server SSL certificate. + + -ca-path=path Path to a directory of PEM encoded CA cert files + to verify the Vault server SSL certificate. If both + -ca-cert and -ca-path are specified, -ca-path is used. + + -insecure Do not verify TLS certificate. This is highly + not recommended. This is especially not recommended + for unsealing a vault. + +Init Options: + + -key-shares=5 The number of key shares to split the master key + into. + + -key-threshold=3 The number of key shares required to reconstruct + the master key. + +` + return strings.TrimSpace(helpText) +} diff --git a/command/meta.go b/command/meta.go index 3b10e805a0..738ec3b589 100644 --- a/command/meta.go +++ b/command/meta.go @@ -2,9 +2,14 @@ package command import ( "bufio" + "crypto/tls" "flag" "io" + "net" + "net/http" + "time" + "github.com/hashicorp/vault/api" "github.com/mitchellh/cli" ) @@ -30,6 +35,39 @@ type Meta struct { flagInsecure bool } +// Client returns the API client to a Vault server given the configured +// flag settings for this command. +func (m *Meta) Client() (*api.Client, error) { + config := api.DefaultConfig() + if m.flagAddress != "" { + config.Address = m.flagAddress + } + + // If we need custom TLS configuration, then set it + if m.flagCACert != "" || m.flagCAPath != "" || m.flagInsecure { + tlsConfig := &tls.Config{ + InsecureSkipVerify: m.flagInsecure, + } + + // TODO: Root CAs + + client := *http.DefaultClient + client.Transport = &http.Transport{ + Proxy: http.ProxyFromEnvironment, + Dial: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).Dial, + TLSClientConfig: tlsConfig, + TLSHandshakeTimeout: 10 * time.Second, + } + + config.HttpClient = &client + } + + return api.NewClient(config) +} + // FlagSet returns a FlagSet with the common flags that every // command implements. The exact behavior of FlagSet can be configured // using the flags as the second parameter, for example to disable diff --git a/commands.go b/commands.go index 341d1c3520..e7909cc7e6 100644 --- a/commands.go +++ b/commands.go @@ -48,6 +48,12 @@ func init() { }, nil }, + "init": func() (cli.Command, error) { + return &command.InitCommand{ + Meta: meta, + }, nil + }, + "server": func() (cli.Command, error) { return &command.ServerCommand{ Meta: meta,