2 * Copyright 2018 Intel Corporation, Inc
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 uuid "github.com/hashicorp/go-uuid"
21 vaultapi "github.com/hashicorp/vault/api"
30 // Vault is the main Struct used in Backend to initialize the struct
37 vaultClient *vaultapi.Client
42 vaultTempTokenTTL time.Time
47 // Init will initialize the vault connection
48 // It will also create the initial policy if it does not exist
49 // TODO: Check to see if we need to wait for vault to be running
50 func (v *Vault) Init() error {
51 vaultCFG := vaultapi.DefaultConfig()
52 vaultCFG.Address = v.vaultAddress
53 client, err := vaultapi.NewClient(vaultCFG)
59 v.policyName = "smsvaultpolicy"
61 v.vaultClient = client
63 // Check if vault is ready and unsealed
64 seal, err := v.GetStatus()
69 return fmt.Errorf("Vault is still sealed. Unseal before use")
77 // GetStatus returns the current seal status of vault
78 func (v *Vault) GetStatus() (bool, error) {
79 sys := v.vaultClient.Sys()
80 sealStatus, err := sys.SealStatus()
85 return sealStatus.Sealed, nil
88 // GetSecretDomain returns any information related to the secretDomain
89 // More information can be added in the future with updates to the struct
90 func (v *Vault) GetSecretDomain(name string) (SecretDomain, error) {
91 return SecretDomain{}, nil
94 // GetSecret returns a secret mounted on a particular domain name
95 // The secret itself is referenced via its name which translates to
96 // a mount path in vault
97 func (v *Vault) GetSecret(dom string, sec string) (Secret, error) {
102 // CreateSecretDomain mounts the kv backend on a path with the given name
103 func (v *Vault) CreateSecretDomain(name string) (SecretDomain, error) {
104 // Check if token is still valid
105 err := v.checkToken()
107 return SecretDomain{}, err
110 name = strings.TrimSpace(name)
111 mountPath := v.vaultMount + "/" + name
112 mountInput := &vaultapi.MountInput{
114 Description: "Mount point for domain: " + name,
117 Config: vaultapi.MountConfigInput{},
120 err = v.vaultClient.Sys().Mount(mountPath, mountInput)
122 return SecretDomain{}, err
125 uuid, _ := uuid.GenerateUUID()
126 return SecretDomain{uuid, name}, nil
129 // CreateSecret creates a secret mounted on a particular domain name
130 // The secret itself is mounted on a path specified by name
131 func (v *Vault) CreateSecret(dom string, sec Secret) (Secret, error) {
136 // DeleteSecretDomain deletes a secret domain which translates to
137 // an unmount operation on the given path in Vault
138 func (v *Vault) DeleteSecretDomain(name string) error {
143 // DeleteSecret deletes a secret mounted on the path provided
144 func (v *Vault) DeleteSecret(dom string, name string) error {
149 // initRole is called only once during the service bring up
150 func (v *Vault) initRole() error {
151 // Use the root token once here
152 v.vaultClient.SetToken(v.vaultToken)
153 defer v.vaultClient.ClearToken()
155 rules := `path "sms/*" { capabilities = ["create", "read", "update", "delete", "list"] }
156 path "sys/mounts/sms*" { capabilities = ["update","delete","create"] }`
157 v.vaultClient.Sys().PutPolicy(v.policyName, rules)
159 rName := v.vaultMount + "-role"
160 data := map[string]interface{}{
162 "policies": [2]string{"default", v.policyName},
165 // Delete role if it already exists
166 v.vaultClient.Logical().Delete("auth/approle/role/" + rName)
168 // Mount approle in case its not already mounted
169 v.vaultClient.Sys().EnableAuth("approle", "approle", "")
172 v.vaultClient.Logical().Write("auth/approle/role/"+rName, data)
173 sec, err := v.vaultClient.Logical().Read("auth/approle/role/" + rName + "/role-id")
177 v.roleID = sec.Data["role_id"].(string)
179 // Create a secret-id to go with it
180 sec, _ = v.vaultClient.Logical().Write("auth/approle/role/"+rName+"/secret-id",
181 map[string]interface{}{})
182 v.secretID = sec.Data["secret_id"].(string)
187 // Function checkToken() gets called multiple times to create
189 func (v *Vault) checkToken() error {
191 defer v.tokenLock.Unlock()
193 // Return immediately if token still has life
194 if v.vaultClient.Token() != "" &&
195 time.Since(v.vaultTempTokenTTL) < time.Minute*50 {
199 // Create a temporary token using our roleID and secretID
200 out, err := v.vaultClient.Logical().Write("auth/approle/login",
201 map[string]interface{}{"role_id": v.roleID, "secret_id": v.secretID})
206 tok, err := out.TokenID()
208 v.vaultTempToken = tok
209 v.vaultTempTokenTTL = time.Now()
210 v.vaultClient.SetToken(v.vaultTempToken)