summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStuart Clark <stuart.clark@Jahingo.com>2017-08-08 12:34:50 +0100
committerDave Henderson <dhenderson@gmail.com>2017-08-08 07:34:50 -0400
commitdd5a7e412352f2e268973b428648cca6e549dc83 (patch)
tree4549114d76f20968efd4207c2a44a0be9b534f36
parentd2cf55b83fe71d41c3a09b35b280d9a48b24088d (diff)
Consul vault auth (#187)
* Enable use of Vault for Consul authentication
-rw-r--r--docs/content/functions/general.md7
-rw-r--r--libkv/consul.go30
-rw-r--r--test/integration/datasources_consul.bats14
-rw-r--r--test/integration/helper.bash5
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
}