2016-08-18 03:28:48 +00:00
|
|
|
package vaultclient
|
|
|
|
|
|
|
|
import (
|
2018-01-08 19:32:31 +00:00
|
|
|
"strings"
|
2016-08-18 03:28:48 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/hashicorp/nomad/client/config"
|
2018-06-13 22:33:25 +00:00
|
|
|
"github.com/hashicorp/nomad/helper/testlog"
|
2016-08-18 03:28:48 +00:00
|
|
|
"github.com/hashicorp/nomad/testutil"
|
|
|
|
vaultapi "github.com/hashicorp/vault/api"
|
2019-04-02 19:49:20 +00:00
|
|
|
vaultconsts "github.com/hashicorp/vault/helper/consts"
|
2019-01-09 20:26:14 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2016-08-18 03:28:48 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestVaultClient_TokenRenewals(t *testing.T) {
|
2017-07-22 02:38:37 +00:00
|
|
|
t.Parallel()
|
2019-01-09 20:26:14 +00:00
|
|
|
require := require.New(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2016-08-18 03:28:48 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
2018-10-04 23:16:08 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2016-08-18 03:28:48 +00:00
|
|
|
v.Config.ConnectionRetryIntv = 100 * time.Millisecond
|
2017-07-22 02:38:37 +00:00
|
|
|
v.Config.TaskTokenTTL = "4s"
|
2016-08-30 01:30:06 +00:00
|
|
|
c, err := NewVaultClient(v.Config, logger, nil)
|
2016-08-18 03:28:48 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
c.Start()
|
|
|
|
defer c.Stop()
|
|
|
|
|
|
|
|
// Sleep a little while to ensure that the renewal loop is active
|
2017-07-22 02:38:37 +00:00
|
|
|
time.Sleep(time.Duration(testutil.TestMultiplier()) * time.Second)
|
2016-08-18 03:28:48 +00:00
|
|
|
|
|
|
|
tcr := &vaultapi.TokenCreateRequest{
|
|
|
|
Policies: []string{"foo", "bar"},
|
|
|
|
TTL: "2s",
|
|
|
|
DisplayName: "derived-for-task",
|
|
|
|
Renewable: new(bool),
|
|
|
|
}
|
|
|
|
*tcr.Renewable = true
|
|
|
|
|
2016-08-23 21:10:00 +00:00
|
|
|
num := 5
|
2016-08-18 03:28:48 +00:00
|
|
|
tokens := make([]string, num)
|
|
|
|
for i := 0; i < num; i++ {
|
|
|
|
c.client.SetToken(v.Config.Token)
|
|
|
|
|
|
|
|
if err := c.client.SetAddress(v.Config.Addr); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
secret, err := c.client.Auth().Token().Create(tcr)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to create vault token: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if secret == nil || secret.Auth == nil || secret.Auth.ClientToken == "" {
|
|
|
|
t.Fatal("failed to derive a wrapped vault token")
|
|
|
|
}
|
|
|
|
|
|
|
|
tokens[i] = secret.Auth.ClientToken
|
|
|
|
|
2016-09-14 22:04:25 +00:00
|
|
|
errCh, err := c.RenewToken(tokens[i], secret.Auth.LeaseDuration)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2016-08-18 03:28:48 +00:00
|
|
|
go func(errCh <-chan error) {
|
|
|
|
for {
|
|
|
|
select {
|
2016-09-14 22:04:25 +00:00
|
|
|
case err := <-errCh:
|
2019-01-09 20:26:14 +00:00
|
|
|
require.NoError(err, "unexpected error while renewing vault token")
|
2016-08-18 03:28:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}(errCh)
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.heap.Length() != num {
|
|
|
|
t.Fatalf("bad: heap length: expected: %d, actual: %d", num, c.heap.Length())
|
|
|
|
}
|
|
|
|
|
2017-07-22 02:38:37 +00:00
|
|
|
time.Sleep(time.Duration(testutil.TestMultiplier()) * time.Second)
|
2016-08-18 03:28:48 +00:00
|
|
|
|
|
|
|
for i := 0; i < num; i++ {
|
|
|
|
if err := c.StopRenewToken(tokens[i]); err != nil {
|
2019-01-09 20:26:14 +00:00
|
|
|
require.NoError(err)
|
2016-08-18 03:28:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.heap.Length() != 0 {
|
2017-02-28 00:00:19 +00:00
|
|
|
t.Fatalf("bad: heap length: expected: 0, actual: %d", c.heap.Length())
|
2016-08-18 03:28:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-02 19:49:20 +00:00
|
|
|
// TestVaultClient_NamespaceSupport tests that the Vault namespace config, if present, will result in the
|
|
|
|
// namespace header being set on the created Vault client.
|
|
|
|
func TestVaultClient_NamespaceSupport(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
require := require.New(t)
|
|
|
|
tr := true
|
|
|
|
testNs := "test-namespace"
|
|
|
|
|
|
|
|
logger := testlog.HCLogger(t)
|
|
|
|
|
|
|
|
conf := config.DefaultConfig()
|
|
|
|
conf.VaultConfig.Enabled = &tr
|
|
|
|
conf.VaultConfig.Token = "testvaulttoken"
|
|
|
|
conf.VaultConfig.Namespace = testNs
|
|
|
|
c, err := NewVaultClient(conf.VaultConfig, logger, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
require.Equal(testNs, c.client.Headers().Get(vaultconsts.NamespaceHeaderName))
|
|
|
|
}
|
|
|
|
|
2016-08-18 03:28:48 +00:00
|
|
|
func TestVaultClient_Heap(t *testing.T) {
|
2017-07-22 02:38:37 +00:00
|
|
|
t.Parallel()
|
2016-10-11 20:28:18 +00:00
|
|
|
tr := true
|
2016-08-18 03:28:48 +00:00
|
|
|
conf := config.DefaultConfig()
|
2016-10-11 20:28:18 +00:00
|
|
|
conf.VaultConfig.Enabled = &tr
|
2016-08-18 03:28:48 +00:00
|
|
|
conf.VaultConfig.Token = "testvaulttoken"
|
|
|
|
conf.VaultConfig.TaskTokenTTL = "10s"
|
|
|
|
|
2018-10-04 23:16:08 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2016-08-30 01:30:06 +00:00
|
|
|
c, err := NewVaultClient(conf.VaultConfig, logger, nil)
|
2016-08-18 03:28:48 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2016-08-23 21:10:00 +00:00
|
|
|
if c == nil {
|
|
|
|
t.Fatal("failed to create vault client")
|
|
|
|
}
|
2016-08-18 03:28:48 +00:00
|
|
|
|
|
|
|
now := time.Now()
|
|
|
|
|
|
|
|
renewalReq1 := &vaultClientRenewalRequest{
|
|
|
|
errCh: make(chan error, 1),
|
|
|
|
id: "id1",
|
|
|
|
increment: 10,
|
|
|
|
}
|
|
|
|
if err := c.heap.Push(renewalReq1, now.Add(50*time.Second)); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2016-08-29 16:37:39 +00:00
|
|
|
if !c.isTracked("id1") {
|
2016-08-18 03:28:48 +00:00
|
|
|
t.Fatalf("id1 should have been tracked")
|
|
|
|
}
|
|
|
|
|
|
|
|
renewalReq2 := &vaultClientRenewalRequest{
|
|
|
|
errCh: make(chan error, 1),
|
|
|
|
id: "id2",
|
|
|
|
increment: 10,
|
|
|
|
}
|
|
|
|
if err := c.heap.Push(renewalReq2, now.Add(40*time.Second)); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2016-08-29 16:37:39 +00:00
|
|
|
if !c.isTracked("id2") {
|
2016-08-18 03:28:48 +00:00
|
|
|
t.Fatalf("id2 should have been tracked")
|
|
|
|
}
|
|
|
|
|
|
|
|
renewalReq3 := &vaultClientRenewalRequest{
|
|
|
|
errCh: make(chan error, 1),
|
|
|
|
id: "id3",
|
|
|
|
increment: 10,
|
|
|
|
}
|
|
|
|
if err := c.heap.Push(renewalReq3, now.Add(60*time.Second)); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2016-08-29 16:37:39 +00:00
|
|
|
if !c.isTracked("id3") {
|
2016-08-18 03:28:48 +00:00
|
|
|
t.Fatalf("id3 should have been tracked")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reading elements should yield id2, id1 and id3 in order
|
|
|
|
req, _ := c.nextRenewal()
|
|
|
|
if req != renewalReq2 {
|
|
|
|
t.Fatalf("bad: expected: %#v, actual: %#v", renewalReq2, req)
|
|
|
|
}
|
|
|
|
if err := c.heap.Update(req, now.Add(70*time.Second)); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
req, _ = c.nextRenewal()
|
|
|
|
if req != renewalReq1 {
|
|
|
|
t.Fatalf("bad: expected: %#v, actual: %#v", renewalReq1, req)
|
|
|
|
}
|
|
|
|
if err := c.heap.Update(req, now.Add(80*time.Second)); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
req, _ = c.nextRenewal()
|
|
|
|
if req != renewalReq3 {
|
|
|
|
t.Fatalf("bad: expected: %#v, actual: %#v", renewalReq3, req)
|
|
|
|
}
|
|
|
|
if err := c.heap.Update(req, now.Add(90*time.Second)); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := c.StopRenewToken("id1"); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := c.StopRenewToken("id2"); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := c.StopRenewToken("id3"); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2016-08-29 16:37:39 +00:00
|
|
|
if c.isTracked("id1") {
|
2016-08-18 03:28:48 +00:00
|
|
|
t.Fatalf("id1 should not have been tracked")
|
|
|
|
}
|
|
|
|
|
2016-08-29 16:37:39 +00:00
|
|
|
if c.isTracked("id1") {
|
2016-08-18 03:28:48 +00:00
|
|
|
t.Fatalf("id1 should not have been tracked")
|
|
|
|
}
|
|
|
|
|
2016-08-29 16:37:39 +00:00
|
|
|
if c.isTracked("id1") {
|
2016-08-18 03:28:48 +00:00
|
|
|
t.Fatalf("id1 should not have been tracked")
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2018-01-08 19:32:31 +00:00
|
|
|
|
|
|
|
func TestVaultClient_RenewNonRenewableLease(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
v := testutil.NewTestVault(t)
|
|
|
|
defer v.Stop()
|
|
|
|
|
2018-10-04 23:16:08 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2018-01-08 19:32:31 +00:00
|
|
|
v.Config.ConnectionRetryIntv = 100 * time.Millisecond
|
|
|
|
v.Config.TaskTokenTTL = "4s"
|
|
|
|
c, err := NewVaultClient(v.Config, logger, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
c.Start()
|
|
|
|
defer c.Stop()
|
|
|
|
|
|
|
|
// Sleep a little while to ensure that the renewal loop is active
|
|
|
|
time.Sleep(time.Duration(testutil.TestMultiplier()) * time.Second)
|
|
|
|
|
|
|
|
tcr := &vaultapi.TokenCreateRequest{
|
|
|
|
Policies: []string{"foo", "bar"},
|
|
|
|
TTL: "2s",
|
|
|
|
DisplayName: "derived-for-task",
|
|
|
|
Renewable: new(bool),
|
|
|
|
}
|
|
|
|
|
|
|
|
c.client.SetToken(v.Config.Token)
|
|
|
|
|
|
|
|
if err := c.client.SetAddress(v.Config.Addr); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
secret, err := c.client.Auth().Token().Create(tcr)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to create vault token: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if secret == nil || secret.Auth == nil || secret.Auth.ClientToken == "" {
|
|
|
|
t.Fatal("failed to derive a wrapped vault token")
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = c.RenewToken(secret.Auth.ClientToken, secret.Auth.LeaseDuration)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("expected error, got nil")
|
|
|
|
} else if !strings.Contains(err.Error(), "lease is not renewable") {
|
|
|
|
t.Fatalf("expected \"%s\" in error message, got \"%v\"", "lease is not renewable", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-12 18:26:37 +00:00
|
|
|
func TestVaultClient_RenewNonexistentLease(t *testing.T) {
|
2018-01-08 19:32:31 +00:00
|
|
|
t.Parallel()
|
|
|
|
v := testutil.NewTestVault(t)
|
|
|
|
defer v.Stop()
|
|
|
|
|
2018-10-04 23:16:08 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2018-01-08 19:32:31 +00:00
|
|
|
v.Config.ConnectionRetryIntv = 100 * time.Millisecond
|
|
|
|
v.Config.TaskTokenTTL = "4s"
|
|
|
|
c, err := NewVaultClient(v.Config, logger, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
c.Start()
|
|
|
|
defer c.Stop()
|
|
|
|
|
|
|
|
// Sleep a little while to ensure that the renewal loop is active
|
|
|
|
time.Sleep(time.Duration(testutil.TestMultiplier()) * time.Second)
|
|
|
|
|
|
|
|
c.client.SetToken(v.Config.Token)
|
|
|
|
|
|
|
|
if err := c.client.SetAddress(v.Config.Addr); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = c.RenewToken(c.client.Token(), 10)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("expected error, got nil")
|
2019-01-10 15:24:29 +00:00
|
|
|
// The Vault error message changed between 0.10.2 and 1.0.1
|
2019-01-09 20:30:47 +00:00
|
|
|
} else if !strings.Contains(err.Error(), "lease not found") && !strings.Contains(err.Error(), "lease is not renewable") {
|
|
|
|
t.Fatalf("expected \"%s\" or \"%s\" in error message, got \"%v\"", "lease not found", "lease is not renewable", err.Error())
|
2018-01-08 19:32:31 +00:00
|
|
|
}
|
|
|
|
}
|