commit 692b51f15983b79531c958357f83a61b014a30be Author: Knut Ahlers Date: Wed Aug 12 16:44:48 2015 +0200 Initial version of vault-unseal tool diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..79a1fc3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +vault-unseal diff --git a/main.go b/main.go new file mode 100644 index 0000000..0986f63 --- /dev/null +++ b/main.go @@ -0,0 +1,88 @@ +package main // import "github.com/Jimdo/vault-unseal" + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "os" + "strings" + "time" + + "github.com/Luzifer/rconfig" +) + +var config = struct { + OneShot bool `flag:"oneshot,1" default:"true" description:"Only try once and exit after"` + SealTokensRaw string `flag:"tokens" default:"" description:"Tokens to try for unsealing the vault instance"` + SealTokens []string + VaultInstance string `flag:"instance" env:"VAULT_ADDR" default:"http://127.0.0.1:8200" description:"Vault instance to unlock"` +}{} + +func init() { + if err := rconfig.Parse(&config); err != nil { + fmt.Printf("Unable to parse CLI parameters: %s\n", err) + os.Exit(1) + } + + if len(config.SealTokensRaw) == 0 { + fmt.Println("You must provide at least one token.") + os.Exit(1) + } + + config.SealTokens = strings.Split(config.SealTokensRaw, ",") +} + +func main() { + for { + s := sealStatus{} + r, err := http.Get(config.VaultInstance + "/v1/sys/seal-status") + if err != nil { + fmt.Printf("An error ocurred while reading seal-status: %s\n", err) + os.Exit(1) + } + defer r.Body.Close() + + if err := json.NewDecoder(r.Body).Decode(&s); err != nil { + fmt.Printf("Unable to decode seal-status: %s\n", err) + os.Exit(1) + } + + if s.Sealed { + for _, token := range config.SealTokens { + fmt.Printf("Vault instance is sealed (missing %d tokens), trying to unlock...\n", s.T-s.Progress) + body := bytes.NewBuffer([]byte{}) + json.NewEncoder(body).Encode(map[string]interface{}{ + "key": token, + }) + r, _ := http.NewRequest("PUT", config.VaultInstance+"/v1/sys/unseal", body) + resp, err := http.DefaultClient.Do(r) + if err != nil { + fmt.Printf("An error ocurred while doing unseal: %s\n", err) + os.Exit(1) + } + defer resp.Body.Close() + + if err := json.NewDecoder(resp.Body).Decode(&s); err != nil { + fmt.Printf("Unable to decode seal-status: %s\n", err) + os.Exit(1) + } + + if !s.Sealed { + fmt.Printf("Unseal successfully finished.\n") + break + } + } + + if s.Sealed { + fmt.Printf("Vault instance is still sealed (missing %d tokens), I don't have any more tokens.\n", s.T-s.Progress) + } + } + + if config.OneShot { + break + } else { + <-time.After(10 * time.Second) + } + } +} diff --git a/structs.go b/structs.go new file mode 100644 index 0000000..b963150 --- /dev/null +++ b/structs.go @@ -0,0 +1,8 @@ +package main + +type sealStatus struct { + Sealed bool `json:"sealed"` + T int `json:"t"` + N int `json:"n"` + Progress int `json:"progress"` +}