13 consulAPI "github.com/hashicorp/consul/api"
14 "github.com/hashicorp/vault/api"
18 vault = &vaultBooter{}
19 vaultCfg = api.DefaultConfig()
22 type vaultBooter struct {
26 func (vb *vaultBooter) Boot(ctx context.Context) error {
30 if vb.check(ctx) == nil {
34 bin := cfg.UsrDir + "/bin/vault"
36 URL: "https://releases.hashicorp.com/vault/0.6.4/vault_0.6.4_linux_amd64.zip",
45 masterToken, err := ioutil.ReadFile(cfg.masterTokenFile())
50 cfgPath := path.Join(cfg.DataDir, "vault.hcl")
51 err = atomicWriteFile(cfgPath, []byte(fmt.Sprintf(`backend "consul" {
52 address = "127.0.0.1:%d"
57 address = "127.0.0.1:%d"
59 }`, cfg.Ports.ConsulHTTP, masterToken, cfg.Ports.VaultServer)), 0644)
64 args := []string{"server", "-config=" + cfgPath}
65 supervisor := newSupervisor(ctx, "arvados-vault", bin, args...)
66 running, err := supervisor.Running(ctx)
71 defer feedbackf(ctx, "starting vault service")()
72 err = supervisor.Start(ctx)
74 return fmt.Errorf("starting vault: %s", err)
78 if err := vb.tryInit(ctx); err != nil {
81 return waitCheck(ctx, 30*time.Second, vb.check)
84 func (vb *vaultBooter) tryInit(ctx context.Context) error {
89 if err := waitCheck(ctx, time.Minute, func(context.Context) error {
91 vault, err = vb.client(ctx)
95 init, err = vault.Sys().InitStatus()
103 resp, err := vault.Sys().Init(&api.InitRequest{
108 return fmt.Errorf("vault-init: %s", err)
110 atomicWriteJSON(path.Join(cfg.DataDir, "vault-keys.json"), resp, 0400)
111 atomicWriteFile(path.Join(cfg.DataDir, "vault-root-token.txt"), []byte(resp.RootToken), 0400)
112 vault.SetToken(resp.RootToken)
115 for _, key := range resp.Keys {
116 resp, err := vault.Sys().Unseal(key)
118 log.Printf("error: unseal: %s", err)
122 log.Printf("unseal successful")
128 return fmt.Errorf("vault unseal failed!")
131 master, err := consul.master(ctx)
135 token, _, err := master.ACL().Create(&consulAPI.ACLEntry{Name: "vault", Type: "management"}, nil)
139 err = waitCheck(ctx, 30*time.Second, func(context.Context) error {
140 return vault.Sys().Mount("consul", &api.MountInput{Type: "consul"})
145 _, err = vault.Logical().Write("consul/config/access", map[string]interface{}{
146 "address": fmt.Sprintf("127.0.0.1:%d", cfg.Ports.ConsulHTTP),
147 "token": string(token),
152 _, err = vault.Logical().Write("consul/roles/write-all", map[string]interface{}{
153 "policy": base64.StdEncoding.EncodeToString([]byte(`key "" { policy = "write" }`)),
158 func (vb *vaultBooter) client(ctx context.Context) (*api.Client, error) {
160 vaultCfg.Address = fmt.Sprintf("http://0.0.0.0:%d", cfg.Ports.VaultServer)
161 return api.NewClient(vaultCfg)
164 func (vb *vaultBooter) check(ctx context.Context) error {
166 vault, err := vb.client(ctx)
170 token, err := ioutil.ReadFile(path.Join(cfg.DataDir, "vault-root-token.txt"))
174 vault.SetToken(string(token))
175 if init, err := vault.Sys().InitStatus(); err != nil {
178 return fmt.Errorf("vault is not initialized")