Merge pull request #9746 from jsmcnair/f-vault-function
Add vault function for HCL2 and documentation
This commit is contained in:
commit
321aa090df
|
@ -1,8 +1,14 @@
|
|||
package template
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
vaultapi "github.com/hashicorp/vault/api"
|
||||
)
|
||||
|
||||
// DeprecatedTemplateFunc wraps a template func to warn users that it's
|
||||
|
@ -17,3 +23,41 @@ func DeprecatedTemplateFunc(funcName, useInstead string, deprecated func(string)
|
|||
return deprecated(in)
|
||||
}
|
||||
}
|
||||
|
||||
// Vault retrieves a secret from an HC vault KV store
|
||||
func Vault(path string, key string) (string, error) {
|
||||
|
||||
if token := os.Getenv("VAULT_TOKEN"); token == "" {
|
||||
return "", 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 "", fmt.Errorf("Error getting Vault client: %s", err)
|
||||
}
|
||||
secret, err := cli.Logical().Read(path)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error reading vault secret: %s", err)
|
||||
}
|
||||
if secret == nil {
|
||||
return "", 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 value.(string), nil
|
||||
}
|
||||
|
||||
// neither v1 nor v2 proudced a valid value
|
||||
return "", fmt.Errorf("Vault data was empty at the given path. Warnings: %s", strings.Join(secret.Warnings, "; "))
|
||||
}
|
||||
|
||||
if val, ok := data.(map[string]interface{})[key]; ok {
|
||||
return val.(string), nil
|
||||
}
|
||||
return "", errors.New("Vault path does not contain the requested key")
|
||||
}
|
||||
|
|
1
go.sum
1
go.sum
|
@ -623,6 +623,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=
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package function
|
||||
|
||||
import (
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/function"
|
||||
|
||||
commontpl "github.com/hashicorp/packer/common/template"
|
||||
)
|
||||
|
||||
// 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()
|
||||
|
||||
val, err := commontpl.Vault(path, key)
|
||||
|
||||
return cty.StringVal(val), err
|
||||
},
|
||||
})
|
|
@ -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,
|
||||
|
|
|
@ -11,11 +11,11 @@ import (
|
|||
"time"
|
||||
|
||||
consulapi "github.com/hashicorp/consul/api"
|
||||
commontpl "github.com/hashicorp/packer/common/template"
|
||||
"github.com/hashicorp/packer/common/uuid"
|
||||
"github.com/hashicorp/packer/helper/common"
|
||||
awssmapi "github.com/hashicorp/packer/template/interpolate/aws/secretsmanager"
|
||||
"github.com/hashicorp/packer/version"
|
||||
vaultapi "github.com/hashicorp/vault/api"
|
||||
strftime "github.com/jehiah/go-strftime"
|
||||
)
|
||||
|
||||
|
@ -289,40 +289,8 @@ func funcGenVault(ctx *Context) interface{} {
|
|||
// semantic checks should catch this.
|
||||
return "", errors.New("Vault vars are only allowed in the variables section")
|
||||
}
|
||||
if token := os.Getenv("VAULT_TOKEN"); token == "" {
|
||||
return "", errors.New("Must set VAULT_TOKEN env var in order to " +
|
||||
"use vault template function")
|
||||
}
|
||||
// const EnvVaultAddress = "VAULT_ADDR"
|
||||
// const EnvVaultToken = "VAULT_TOKEN"
|
||||
vaultConfig := vaultapi.DefaultConfig()
|
||||
cli, err := vaultapi.NewClient(vaultConfig)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error getting Vault client: %s", err)
|
||||
}
|
||||
secret, err := cli.Logical().Read(path)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error reading vault secret: %s", err)
|
||||
}
|
||||
if secret == nil {
|
||||
return "", 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 value.(string), nil
|
||||
}
|
||||
|
||||
// neither v1 nor v2 proudced a valid value
|
||||
return "", fmt.Errorf("Vault data was empty at the "+
|
||||
"given path. Warnings: %s", strings.Join(secret.Warnings, "; "))
|
||||
}
|
||||
|
||||
value := data.(map[string]interface{})[key].(string)
|
||||
return value, nil
|
||||
return commontpl.Vault(path, key)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
layout: docs
|
||||
page_title: vault - Functions - Configuration Language
|
||||
sidebar_title: vault Functions
|
||||
description: Overview of available vault functions
|
||||
---
|
|
@ -0,0 +1,76 @@
|
|||
---
|
||||
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
|
||||
locals {
|
||||
foo = vault("/secret/data/hello" "foo")
|
||||
}
|
||||
```
|
||||
|
||||
which will assign `local.foo` with the value "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
|
||||
locals {
|
||||
foo = vault("secrets/hello", "foo")
|
||||
}
|
||||
```
|
||||
|
||||
This example accesses the Vault path `secret/foo` and returns the value
|
||||
stored at the key `foo`, storing it as the local variable `local.foo`.
|
||||
|
||||
In order for this to work, you must set the environment variables `VAULT_TOKEN`
|
||||
and `VAULT_ADDR` to valid values.
|
||||
|
||||
-> **NOTE:** HCL functions can be used in local variable definitions or inline
|
||||
with a provisioner/post-processor. They cannot be used in global variable definitions.
|
||||
|
||||
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).
|
Loading…
Reference in New Issue