diff options
| author | Stuart Clark <stuart.clark@Jahingo.com> | 2017-08-08 12:34:50 +0100 |
|---|---|---|
| committer | Dave Henderson <dhenderson@gmail.com> | 2017-08-08 07:34:50 -0400 |
| commit | dd5a7e412352f2e268973b428648cca6e549dc83 (patch) | |
| tree | 4549114d76f20968efd4207c2a44a0be9b534f36 | |
| parent | d2cf55b83fe71d41c3a09b35b280d9a48b24088d (diff) | |
Consul vault auth (#187)
* Enable use of Vault for Consul authentication
| -rw-r--r-- | docs/content/functions/general.md | 7 | ||||
| -rw-r--r-- | libkv/consul.go | 30 | ||||
| -rw-r--r-- | test/integration/datasources_consul.bats | 14 | ||||
| -rw-r--r-- | test/integration/helper.bash | 5 |
4 files changed, 54 insertions, 2 deletions
diff --git a/docs/content/functions/general.md b/docs/content/functions/general.md index c3c2cfe0..7f33cfde 100644 --- a/docs/content/functions/general.md +++ b/docs/content/functions/general.md @@ -532,6 +532,8 @@ The following optional environment variables can be set: | `CONSUL_CLIENT_CERT` | Client certificate file for certificate authentication. If this is set, `$CONSUL_CLIENT_KEY` must also be set. | | `CONSUL_CLIENT_KEY` | Client key file for certificate authentication. If this is set, `$CONSUL_CLIENT_CERT` must also be set. | | `CONSUL_HTTP_SSL_VERIFY` | Set to `false` to disable Consul TLS certificate checking. Any value acceptable to [`strconv.ParseBool`](https://golang.org/pkg/strconv/#ParseBool) can be provided. <br/> _Recommended only for testing and development scenarios!_ | +| `CONSUL_VAULT_ROLE` | If set will fetch the Consul authentication from Vault using the Consul dynamic secret backend. Value should be the name of the role to use. | +| `CONSUL_VAULT_MOUNT` | If using Vault for authentication set the name of the Consul dynamic secret backend. Defaults to `consul`. | If a path is included it is used as a prefix for all uses of the datasource. @@ -552,6 +554,11 @@ $ gomplate -d consul=consul:///foo -i '{{(datasource "consul" "bar/baz")}}' value for foo/bar/baz key ``` +Instead of using a non-authenticated Consul connection or connecting using the token set with the +`CONSUL_HTTP_TOKEN` environment variable, it is possible to authenticate using a dynamically generated +token fetched from Vault. This requires Vault to be configured to use the Consul secret backend and +is enabled by passing the name of the role to use in the `CONSUL_VAULT_ROLE` environment variable. + ### Usage with BoltDB data [BoltDB](https://github.com/boltdb/bolt) is a simple local key/value store used diff --git a/libkv/consul.go b/libkv/consul.go index 42ffc2dd..3cf441f7 100644 --- a/libkv/consul.go +++ b/libkv/consul.go @@ -1,14 +1,19 @@ package libkv import ( + "fmt" "net/url" + "os" "time" + yaml "gopkg.in/yaml.v2" + "github.com/docker/libkv" "github.com/docker/libkv/store" "github.com/docker/libkv/store/consul" "github.com/hairyhenderson/gomplate/env" "github.com/hairyhenderson/gomplate/typeconv" + "github.com/hairyhenderson/gomplate/vault" consulapi "github.com/hashicorp/consul/api" ) @@ -17,6 +22,31 @@ func NewConsul(u *url.URL) *LibKV { consul.Register() c := consulURL(u) config := consulConfig(c.Scheme == "https") + if role := env.Getenv("CONSUL_VAULT_ROLE", ""); role != "" { + mount := env.Getenv("CONSUL_VAULT_MOUNT", "consul") + + client := vault.New() + client.Login() + + path := fmt.Sprintf("%s/creds/%s", mount, role) + + data, err := client.Read(path) + if err != nil { + logFatal("vault consul auth failed", err) + } + + decoded := make(map[string]interface{}) + err = yaml.Unmarshal(data, &decoded) + if err != nil { + logFatal("Unable to unmarshal object", err) + } + + var token = decoded["token"].(string) + + client.Logout() + + os.Setenv("CONSUL_HTTP_TOKEN", token) + } kv, err := libkv.NewStore(store.CONSUL, []string{c.String()}, config) if err != nil { logFatal("Consul setup failed", err) diff --git a/test/integration/datasources_consul.bats b/test/integration/datasources_consul.bats index 668facf5..70ab14ca 100644 --- a/test/integration/datasources_consul.bats +++ b/test/integration/datasources_consul.bats @@ -8,8 +8,9 @@ function setup () { } function teardown () { + export CONSUL_HTTP_ADDR=http://127.0.0.1:8501 consul kv delete foo - unset CONSUL_HTTP_ADDR + vault unmount consul stop_consul } @@ -35,3 +36,14 @@ function teardown () { [ "$status" -eq 0 ] [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]] } + +@test "Consul datasource works with Vault auth" { + vault mount consul + vault write consul/config/access address=127.0.0.1:8501 token=${CONSUL_ROOT_TOKEN} + POLICY='key "" { policy = "read" }' + vault write consul/roles/readonly policy=`echo $POLICY | base64` + consul kv put foo "$BATS_TEST_DESCRIPTION" + CONSUL_VAULT_ROLE=readonly gomplate -d consul=consul:// -i '{{(datasource "consul" "foo")}}' + [ "$status" -eq 0 ] + [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]] +} diff --git a/test/integration/helper.bash b/test/integration/helper.bash index 00867bc8..7f5cc85f 100644 --- a/test/integration/helper.bash +++ b/test/integration/helper.bash @@ -64,11 +64,14 @@ function start_consul () { fi PID_FILE=/tmp/gomplate-test-consul.pid rm -f $PID_FILE || true - consul agent -dev -log-level=err -http-port=$port -pid-file=$PID_FILE >/dev/null & + export CONSUL_ROOT_TOKEN=00000000-1111-2222-3333-444455556666 + echo "{\"acl_datacenter\": \"dc1\", \"acl_master_token\": \"${CONSUL_ROOT_TOKEN}\"}" >> /tmp/gomplate-test-consul.json + consul agent -dev -config-file=/tmp/gomplate-test-consul.json -log-level=err -http-port=$port -pid-file=$PID_FILE >/dev/null & wait_for_url http://127.0.0.1:$port/v1/status/leader } function stop_consul () { PID_FILE=/tmp/gomplate-test-consul.pid kill $(cat $PID_FILE) &>/dev/null + rm /tmp/gomplate-test-consul.json } |
