Add vault function for HCL2 and document

This commit is contained in:
jsmcnair 2020-08-11 09:18:15 +01:00
parent 027eb40a97
commit 33e3f62ff7
5 changed files with 149 additions and 0 deletions

1
go.sum
View File

@ -621,6 +621,7 @@ github.com/zclconf/go-cty v1.0.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLE
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
github.com/zclconf/go-cty v1.4.0 h1:+q+tmgyUB94HIdH/uVTIi/+kt3pt4sHwEZAcTyLoGsQ=
github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ=
github.com/zclconf/go-cty v1.5.1 h1:oALUZX+aJeEBUe2a1+uD2+UTaYfEjnKFDEMRydkGvWE=
github.com/zclconf/go-cty-yaml v1.0.1 h1:up11wlgAaDvlAGENcFDnZgkn0qUJurso7k6EpURKNF8=
github.com/zclconf/go-cty-yaml v1.0.1/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0=
go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=

View File

@ -0,0 +1,72 @@
package function
import (
"errors"
"fmt"
"os"
"strings"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/function"
vaultapi "github.com/hashicorp/vault/api"
)
// VaultFunc constructs a function that retrieves KV secrets from HC vault
var VaultFunc = function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "path",
Type: cty.String,
},
{
Name: "key",
Type: cty.String,
},
},
Type: function.StaticReturnType(cty.String),
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
path := args[0].AsString()
key := args[1].AsString()
if token := os.Getenv("VAULT_TOKEN"); token == "" {
return cty.StringVal(""), errors.New("Must set VAULT_TOKEN env var in order to " +
"use vault template function")
}
vaultConfig := vaultapi.DefaultConfig()
cli, err := vaultapi.NewClient(vaultConfig)
if err != nil {
return cty.StringVal(""), fmt.Errorf("Error getting Vault client: %s", err)
}
secret, err := cli.Logical().Read(path)
if err != nil {
return cty.StringVal(""), fmt.Errorf("Error reading vault secret: %s", err)
}
if secret == nil {
return cty.StringVal(""), errors.New("Vault Secret does not exist at the given path")
}
data, ok := secret.Data["data"]
if !ok {
// maybe ths is v1, not v2 kv store
value, ok := secret.Data[key]
if ok {
return cty.StringVal(value.(string)), nil
}
// neither v1 nor v2 proudced a valid value
return cty.StringVal(""), fmt.Errorf("Vault data was empty at the "+
"given path. Warnings: %s", strings.Join(secret.Warnings, "; "))
}
value := data.(map[string]interface{})[key].(string)
return cty.StringVal(value), nil
},
})
// Vault returns a secret from a KV store in HC vault
func Vault() (cty.Value, error) {
return VaultFunc.Call([]cty.Value{})
}

View File

@ -106,6 +106,7 @@ func Functions(basedir string) map[string]function.Function {
"uuidv4": uuid.V4Func,
"uuidv5": uuid.V5Func,
"values": stdlib.ValuesFunc,
"vault": pkrfunction.VaultFunc,
"yamldecode": ctyyaml.YAMLDecodeFunc,
"yamlencode": ctyyaml.YAMLEncodeFunc,
"zipmap": stdlib.ZipmapFunc,

View File

@ -0,0 +1,6 @@
---
layout: docs
page_title: vault - Functions - Configuration Language
sidebar_title: vault Functions
description: Overview of available vault functions
---

View File

@ -0,0 +1,69 @@
---
layout: docs
page_title: vault - Functions - Configuration Language
sidebar_title: vault
description: The vault function retrieves secrets from HashiCorp Vault KV stores.
--
# `vault` Function
Secrets can be read from [Vault](https://www.vaultproject.io/) and used within
your template as user variables. the `vault` function is available _only_
within the default value of a user variable, allowing you to default a user
variable to a vault secret.
An example of using a v2 kv engine:
If you store a value in vault using `vault kv put secret/hello foo=world`, you
can access it using the following:
```hcl
vault("/secret/data/hello" "foo")
```
which will assign "my_secret": "world"
An example of using a v1 kv engine:
If you store a value in vault using:
vault secrets enable -version=1 -path=secrets kv
vault kv put secrets/hello foo=world
You can access it using the following:
```hcl
vault("secrets/hello", "foo")
```
This example accesses the Vault path `secret/data/foo` and returns the value
stored at the key `bar`, storing it as "my_secret".
In order for this to work, you must set the environment variables `VAULT_TOKEN`
and `VAULT_ADDR` to valid values.
The api tool we use allows for more custom configuration of the Vault client via
environment variables.
The full list of available environment variables is:
```text
"VAULT_ADDR"
"VAULT_AGENT_ADDR"
"VAULT_CACERT"
"VAULT_CAPATH"
"VAULT_CLIENT_CERT"
"VAULT_CLIENT_KEY"
"VAULT_CLIENT_TIMEOUT"
"VAULT_SKIP_VERIFY"
"VAULT_NAMESPACE"
"VAULT_TLS_SERVER_NAME"
"VAULT_WRAP_TTL"
"VAULT_MAX_RETRIES"
"VAULT_TOKEN"
"VAULT_MFA"
"VAULT_RATE_LIMIT"
```
and detailed documentation for usage of each of those variables can be found
[here](https://www.vaultproject.io/docs/commands/#environment-variables).