2023-04-10 15:36:59 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2016-08-14 01:33:48 +00:00
|
|
|
package nomad
|
|
|
|
|
|
|
|
import (
|
2016-08-18 20:52:15 +00:00
|
|
|
"context"
|
2016-08-15 01:56:32 +00:00
|
|
|
"encoding/json"
|
2018-11-20 20:14:57 +00:00
|
|
|
"errors"
|
2016-10-23 01:08:30 +00:00
|
|
|
"fmt"
|
2017-07-23 23:21:25 +00:00
|
|
|
"math/rand"
|
2016-08-16 21:42:40 +00:00
|
|
|
"reflect"
|
2016-08-14 01:33:48 +00:00
|
|
|
"strings"
|
2020-07-28 21:59:16 +00:00
|
|
|
"sync/atomic"
|
2016-08-14 01:33:48 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2022-03-15 12:42:43 +00:00
|
|
|
"github.com/hashicorp/nomad/ci"
|
2018-11-20 20:14:57 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
2018-11-09 16:34:09 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2016-08-18 20:52:15 +00:00
|
|
|
"golang.org/x/time/rate"
|
|
|
|
|
2022-08-17 16:26:34 +00:00
|
|
|
"github.com/hashicorp/nomad/helper/pointer"
|
2018-06-13 22:33:25 +00:00
|
|
|
"github.com/hashicorp/nomad/helper/testlog"
|
2017-09-29 16:58:48 +00:00
|
|
|
"github.com/hashicorp/nomad/helper/uuid"
|
2016-08-19 21:46:51 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/mock"
|
2016-08-16 21:42:40 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
2016-08-14 01:33:48 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/structs/config"
|
|
|
|
"github.com/hashicorp/nomad/testutil"
|
2016-08-15 01:56:32 +00:00
|
|
|
vapi "github.com/hashicorp/vault/api"
|
2020-03-21 15:01:59 +00:00
|
|
|
vaultconsts "github.com/hashicorp/vault/sdk/helper/consts"
|
2016-08-14 01:33:48 +00:00
|
|
|
)
|
|
|
|
|
2016-08-19 21:46:51 +00:00
|
|
|
const (
|
2017-01-22 01:33:35 +00:00
|
|
|
// nomadRoleManagementPolicy is a policy that allows nomad to manage tokens
|
|
|
|
nomadRoleManagementPolicy = `
|
|
|
|
path "auth/token/renew-self" {
|
|
|
|
capabilities = ["update"]
|
2016-10-24 22:39:18 +00:00
|
|
|
}
|
|
|
|
|
2017-01-20 01:21:46 +00:00
|
|
|
path "auth/token/lookup" {
|
|
|
|
capabilities = ["update"]
|
2016-11-01 05:43:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
path "auth/token/roles/test" {
|
|
|
|
capabilities = ["read"]
|
|
|
|
}
|
|
|
|
|
2017-01-20 18:06:47 +00:00
|
|
|
path "auth/token/revoke-accessor" {
|
2016-11-01 05:43:51 +00:00
|
|
|
capabilities = ["update"]
|
2016-10-24 22:39:18 +00:00
|
|
|
}
|
2017-01-22 01:33:35 +00:00
|
|
|
`
|
|
|
|
|
|
|
|
// tokenLookupPolicy allows a token to be looked up
|
|
|
|
tokenLookupPolicy = `
|
|
|
|
path "auth/token/lookup" {
|
|
|
|
capabilities = ["update"]
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
// nomadRoleCreatePolicy gives the ability to create the role and derive tokens
|
|
|
|
// from the test role
|
|
|
|
nomadRoleCreatePolicy = `
|
|
|
|
path "auth/token/create/test" {
|
|
|
|
capabilities = ["create", "update"]
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
// secretPolicy gives access to the secret mount
|
|
|
|
secretPolicy = `
|
|
|
|
path "secret/*" {
|
|
|
|
capabilities = ["create", "read", "update", "delete", "list"]
|
|
|
|
}
|
2016-10-24 22:39:18 +00:00
|
|
|
`
|
2016-08-19 21:46:51 +00:00
|
|
|
)
|
|
|
|
|
2022-04-05 18:18:10 +00:00
|
|
|
// defaultTestVaultAllowlistRoleAndToken creates a test Vault role and returns a token
|
2017-01-20 18:06:47 +00:00
|
|
|
// created in that role
|
2022-04-05 18:18:10 +00:00
|
|
|
func defaultTestVaultAllowlistRoleAndToken(v *testutil.TestVault, t *testing.T, rolePeriod int) string {
|
2017-01-22 01:33:35 +00:00
|
|
|
vaultPolicies := map[string]string{
|
|
|
|
"nomad-role-create": nomadRoleCreatePolicy,
|
|
|
|
"nomad-role-management": nomadRoleManagementPolicy,
|
|
|
|
}
|
2017-01-20 18:06:47 +00:00
|
|
|
d := make(map[string]interface{}, 2)
|
2017-01-22 01:33:35 +00:00
|
|
|
d["allowed_policies"] = "nomad-role-create,nomad-role-management"
|
2017-01-20 18:06:47 +00:00
|
|
|
d["period"] = rolePeriod
|
2017-01-22 01:33:35 +00:00
|
|
|
return testVaultRoleAndToken(v, t, vaultPolicies, d,
|
|
|
|
[]string{"nomad-role-create", "nomad-role-management"})
|
2017-01-20 18:06:47 +00:00
|
|
|
}
|
|
|
|
|
2022-04-05 18:18:10 +00:00
|
|
|
// defaultTestVaultDenylistRoleAndToken creates a test Vault role using
|
2017-01-22 01:33:35 +00:00
|
|
|
// disallowed_policies and returns a token created in that role
|
2022-04-05 18:18:10 +00:00
|
|
|
func defaultTestVaultDenylistRoleAndToken(v *testutil.TestVault, t *testing.T, rolePeriod int) string {
|
2017-01-22 01:33:35 +00:00
|
|
|
vaultPolicies := map[string]string{
|
|
|
|
"nomad-role-create": nomadRoleCreatePolicy,
|
|
|
|
"nomad-role-management": nomadRoleManagementPolicy,
|
|
|
|
"secrets": secretPolicy,
|
|
|
|
}
|
|
|
|
|
2017-01-23 18:40:28 +00:00
|
|
|
// Create the role
|
2017-01-22 01:33:35 +00:00
|
|
|
d := make(map[string]interface{}, 2)
|
2017-01-23 18:40:28 +00:00
|
|
|
d["disallowed_policies"] = "nomad-role-create"
|
2017-01-22 01:33:35 +00:00
|
|
|
d["period"] = rolePeriod
|
2017-01-23 18:40:28 +00:00
|
|
|
testVaultRoleAndToken(v, t, vaultPolicies, d, []string{"default"})
|
|
|
|
|
|
|
|
// Create a token that can use the role
|
|
|
|
a := v.Client.Auth().Token()
|
|
|
|
req := &vapi.TokenCreateRequest{
|
|
|
|
Policies: []string{"nomad-role-create", "nomad-role-management"},
|
|
|
|
}
|
|
|
|
s, err := a.Create(req)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to create child token: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if s == nil || s.Auth == nil {
|
|
|
|
t.Fatalf("bad secret response: %+v", s)
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.Auth.ClientToken
|
2017-01-22 01:33:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// testVaultRoleAndToken writes the vaultPolicies to vault and then creates a
|
|
|
|
// test role with the passed data. After that it derives a token from the role
|
|
|
|
// with the tokenPolicies
|
|
|
|
func testVaultRoleAndToken(v *testutil.TestVault, t *testing.T, vaultPolicies map[string]string,
|
|
|
|
data map[string]interface{}, tokenPolicies []string) string {
|
|
|
|
// Write the policies
|
2017-01-20 18:06:47 +00:00
|
|
|
sys := v.Client.Sys()
|
2017-01-22 01:33:35 +00:00
|
|
|
for p, data := range vaultPolicies {
|
|
|
|
if err := sys.PutPolicy(p, data); err != nil {
|
|
|
|
t.Fatalf("failed to create %q policy: %v", p, err)
|
|
|
|
}
|
2017-01-20 18:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Build a role
|
|
|
|
l := v.Client.Logical()
|
|
|
|
l.Write("auth/token/roles/test", data)
|
|
|
|
|
|
|
|
// Create a new token with the role
|
|
|
|
a := v.Client.Auth().Token()
|
|
|
|
req := vapi.TokenCreateRequest{
|
2017-01-22 01:33:35 +00:00
|
|
|
Policies: tokenPolicies,
|
2017-01-20 18:06:47 +00:00
|
|
|
}
|
|
|
|
s, err := a.CreateWithRole(&req, "test")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to create child token: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the client token
|
|
|
|
if s == nil || s.Auth == nil {
|
|
|
|
t.Fatalf("bad secret response: %+v", s)
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.Auth.ClientToken
|
|
|
|
}
|
|
|
|
|
2016-08-14 01:33:48 +00:00
|
|
|
func TestVaultClient_BadConfig(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2016-08-14 01:33:48 +00:00
|
|
|
conf := &config.VaultConfig{}
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2016-08-14 01:33:48 +00:00
|
|
|
|
|
|
|
// Should be no error since Vault is not enabled
|
2020-07-17 14:41:45 +00:00
|
|
|
_, err := NewVaultClient(nil, logger, nil, nil)
|
2016-08-22 20:57:27 +00:00
|
|
|
if err == nil || !strings.Contains(err.Error(), "valid") {
|
|
|
|
t.Fatalf("expected config error: %v", err)
|
2016-08-14 01:33:48 +00:00
|
|
|
}
|
|
|
|
|
2016-10-11 20:28:18 +00:00
|
|
|
tr := true
|
|
|
|
conf.Enabled = &tr
|
2020-07-17 14:41:45 +00:00
|
|
|
_, err = NewVaultClient(conf, logger, nil, nil)
|
2016-08-14 01:33:48 +00:00
|
|
|
if err == nil || !strings.Contains(err.Error(), "token must be set") {
|
|
|
|
t.Fatalf("Expected token unset error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
conf.Token = "123"
|
2020-07-17 14:41:45 +00:00
|
|
|
_, err = NewVaultClient(conf, logger, nil, nil)
|
2016-08-14 01:33:48 +00:00
|
|
|
if err == nil || !strings.Contains(err.Error(), "address must be set") {
|
|
|
|
t.Fatalf("Expected address unset error: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-05 18:44:19 +00:00
|
|
|
// TestVaultClient_WithNamespaceSupport tests that the Vault namespace config, if present, will result in the
|
2019-04-02 19:49:20 +00:00
|
|
|
// namespace header being set on the created Vault client.
|
2019-04-05 18:44:19 +00:00
|
|
|
func TestVaultClient_WithNamespaceSupport(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2019-04-02 19:49:20 +00:00
|
|
|
require := require.New(t)
|
|
|
|
tr := true
|
|
|
|
testNs := "test-namespace"
|
|
|
|
conf := &config.VaultConfig{
|
|
|
|
Addr: "https://vault.service.consul:8200",
|
|
|
|
Enabled: &tr,
|
|
|
|
Token: "testvaulttoken",
|
|
|
|
Namespace: testNs,
|
|
|
|
}
|
|
|
|
logger := testlog.HCLogger(t)
|
|
|
|
|
|
|
|
// Should be no error since Vault is not enabled
|
2020-07-17 14:41:45 +00:00
|
|
|
c, err := NewVaultClient(conf, logger, nil, nil)
|
2019-04-02 19:49:20 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
require.Equal(testNs, c.client.Headers().Get(vaultconsts.NamespaceHeaderName))
|
2019-04-05 18:44:19 +00:00
|
|
|
require.Equal("", c.clientSys.Headers().Get(vaultconsts.NamespaceHeaderName))
|
|
|
|
require.NotEqual(c.clientSys, c.client)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestVaultClient_WithoutNamespaceSupport tests that the Vault namespace config, if present, will result in the
|
|
|
|
// namespace header being set on the created Vault client.
|
|
|
|
func TestVaultClient_WithoutNamespaceSupport(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2019-04-05 18:44:19 +00:00
|
|
|
require := require.New(t)
|
|
|
|
tr := true
|
|
|
|
conf := &config.VaultConfig{
|
|
|
|
Addr: "https://vault.service.consul:8200",
|
|
|
|
Enabled: &tr,
|
|
|
|
Token: "testvaulttoken",
|
|
|
|
Namespace: "",
|
|
|
|
}
|
|
|
|
logger := testlog.HCLogger(t)
|
|
|
|
|
|
|
|
// Should be no error since Vault is not enabled
|
2020-07-17 14:41:45 +00:00
|
|
|
c, err := NewVaultClient(conf, logger, nil, nil)
|
2019-04-05 18:44:19 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
require.Equal("", c.client.Headers().Get(vaultconsts.NamespaceHeaderName))
|
|
|
|
require.Equal("", c.clientSys.Headers().Get(vaultconsts.NamespaceHeaderName))
|
|
|
|
require.Equal(c.clientSys, c.client)
|
2019-04-02 19:49:20 +00:00
|
|
|
}
|
|
|
|
|
2017-08-07 21:13:05 +00:00
|
|
|
// started separately.
|
2016-08-14 01:33:48 +00:00
|
|
|
// Test that the Vault Client can establish a connection even if it is started
|
|
|
|
// before Vault is available.
|
|
|
|
func TestVaultClient_EstablishConnection(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
for i := 10; i >= 0; i-- {
|
|
|
|
v := testutil.NewTestVaultDelayed(t)
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v.Config.ConnectionRetryIntv = 100 * time.Millisecond
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2017-07-23 23:21:25 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
2016-08-14 01:33:48 +00:00
|
|
|
|
2017-07-23 23:21:25 +00:00
|
|
|
// Sleep a little while and check that no connection has been established.
|
|
|
|
time.Sleep(100 * time.Duration(testutil.TestMultiplier()) * time.Millisecond)
|
|
|
|
if established, _ := client.ConnectionEstablished(); established {
|
|
|
|
t.Fatalf("ConnectionEstablished() returned true before Vault server started")
|
|
|
|
}
|
2016-08-14 01:33:48 +00:00
|
|
|
|
2017-07-23 23:21:25 +00:00
|
|
|
// Start Vault
|
|
|
|
if err := v.Start(); err != nil {
|
|
|
|
v.Stop()
|
|
|
|
client.Stop()
|
2016-08-14 01:33:48 +00:00
|
|
|
|
2017-07-23 23:21:25 +00:00
|
|
|
if i == 0 {
|
|
|
|
t.Fatalf("Failed to start vault: %v", err)
|
|
|
|
}
|
2016-08-14 01:33:48 +00:00
|
|
|
|
2017-07-23 23:21:25 +00:00
|
|
|
wait := time.Duration(rand.Int31n(2000)) * time.Millisecond
|
|
|
|
time.Sleep(wait)
|
|
|
|
continue
|
|
|
|
}
|
2016-08-14 01:33:48 +00:00
|
|
|
|
2017-07-23 23:21:25 +00:00
|
|
|
var waitErr error
|
|
|
|
testutil.WaitForResult(func() (bool, error) {
|
|
|
|
return client.ConnectionEstablished()
|
|
|
|
}, func(err error) {
|
|
|
|
waitErr = err
|
|
|
|
})
|
|
|
|
|
|
|
|
v.Stop()
|
|
|
|
client.Stop()
|
|
|
|
if waitErr != nil {
|
|
|
|
if i == 0 {
|
|
|
|
t.Fatalf("Failed to start vault: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
wait := time.Duration(rand.Int31n(2000)) * time.Millisecond
|
|
|
|
time.Sleep(wait)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
break
|
|
|
|
}
|
2016-08-22 20:57:27 +00:00
|
|
|
}
|
|
|
|
|
2016-10-24 22:39:18 +00:00
|
|
|
func TestVaultClient_ValidateRole(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2016-10-24 22:39:18 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
2017-01-22 01:33:35 +00:00
|
|
|
vaultPolicies := map[string]string{
|
|
|
|
"nomad-role-create": nomadRoleCreatePolicy,
|
|
|
|
"nomad-role-management": nomadRoleManagementPolicy,
|
|
|
|
}
|
2016-10-24 22:39:18 +00:00
|
|
|
data := map[string]interface{}{
|
2019-11-11 23:44:54 +00:00
|
|
|
"allowed_policies": "default,root",
|
|
|
|
"orphan": true,
|
|
|
|
"renewable": true,
|
|
|
|
"token_explicit_max_ttl": 10,
|
2016-10-24 22:39:18 +00:00
|
|
|
}
|
2017-01-22 01:33:35 +00:00
|
|
|
v.Config.Token = testVaultRoleAndToken(v, t, vaultPolicies, data, nil)
|
2016-10-24 22:39:18 +00:00
|
|
|
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2016-10-24 22:39:18 +00:00
|
|
|
v.Config.ConnectionRetryIntv = 100 * time.Millisecond
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2019-10-28 13:33:26 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2016-10-24 22:39:18 +00:00
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
// Wait for an error
|
|
|
|
var conn bool
|
|
|
|
var connErr error
|
|
|
|
testutil.WaitForResult(func() (bool, error) {
|
|
|
|
conn, connErr = client.ConnectionEstablished()
|
2018-03-09 02:27:49 +00:00
|
|
|
if !conn {
|
|
|
|
return false, fmt.Errorf("Should connect")
|
2016-10-24 22:39:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if connErr == nil {
|
|
|
|
return false, fmt.Errorf("expect an error")
|
|
|
|
}
|
|
|
|
|
|
|
|
return true, nil
|
|
|
|
}, func(err error) {
|
2019-10-28 13:33:26 +00:00
|
|
|
require.NoError(t, err)
|
2016-10-24 22:39:18 +00:00
|
|
|
})
|
|
|
|
|
2019-10-28 13:33:26 +00:00
|
|
|
require.Contains(t, connErr.Error(), "explicit max ttl")
|
2019-11-11 23:44:54 +00:00
|
|
|
require.Contains(t, connErr.Error(), "non-zero period")
|
2019-10-28 13:33:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TestVaultClient_ValidateRole_Success asserts that a valid token role
|
|
|
|
// gets marked as valid
|
|
|
|
func TestVaultClient_ValidateRole_Success(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2019-10-28 13:33:26 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
|
|
|
vaultPolicies := map[string]string{
|
|
|
|
"nomad-role-create": nomadRoleCreatePolicy,
|
|
|
|
"nomad-role-management": nomadRoleManagementPolicy,
|
|
|
|
}
|
|
|
|
data := map[string]interface{}{
|
|
|
|
"allowed_policies": "default,root",
|
|
|
|
"orphan": true,
|
|
|
|
"renewable": true,
|
|
|
|
"token_period": 1000,
|
2016-10-24 22:39:18 +00:00
|
|
|
}
|
2019-10-28 13:33:26 +00:00
|
|
|
v.Config.Token = testVaultRoleAndToken(v, t, vaultPolicies, data, nil)
|
|
|
|
|
|
|
|
logger := testlog.HCLogger(t)
|
|
|
|
v.Config.ConnectionRetryIntv = 100 * time.Millisecond
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2019-10-28 13:33:26 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
// Wait for an error
|
|
|
|
var conn bool
|
|
|
|
var connErr error
|
|
|
|
testutil.WaitForResult(func() (bool, error) {
|
|
|
|
conn, connErr = client.ConnectionEstablished()
|
|
|
|
if !conn {
|
|
|
|
return false, fmt.Errorf("Should connect")
|
|
|
|
}
|
|
|
|
|
|
|
|
if connErr != nil {
|
|
|
|
return false, connErr
|
|
|
|
}
|
|
|
|
|
|
|
|
return true, nil
|
|
|
|
}, func(err error) {
|
|
|
|
require.NoError(t, err)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestVaultClient_ValidateRole_Deprecated_Success asserts that a valid token
|
|
|
|
// role gets marked as valid, even if it uses deprecated field, period
|
|
|
|
func TestVaultClient_ValidateRole_Deprecated_Success(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2019-10-28 13:33:26 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
|
|
|
vaultPolicies := map[string]string{
|
|
|
|
"nomad-role-create": nomadRoleCreatePolicy,
|
|
|
|
"nomad-role-management": nomadRoleManagementPolicy,
|
|
|
|
}
|
|
|
|
data := map[string]interface{}{
|
|
|
|
"allowed_policies": "default,root",
|
|
|
|
"orphan": true,
|
|
|
|
"renewable": true,
|
|
|
|
"period": 1000,
|
|
|
|
}
|
|
|
|
v.Config.Token = testVaultRoleAndToken(v, t, vaultPolicies, data, nil)
|
|
|
|
|
|
|
|
logger := testlog.HCLogger(t)
|
|
|
|
v.Config.ConnectionRetryIntv = 100 * time.Millisecond
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2019-10-28 13:33:26 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
// Wait for an error
|
|
|
|
var conn bool
|
|
|
|
var connErr error
|
|
|
|
testutil.WaitForResult(func() (bool, error) {
|
|
|
|
conn, connErr = client.ConnectionEstablished()
|
|
|
|
if !conn {
|
|
|
|
return false, fmt.Errorf("Should connect")
|
|
|
|
}
|
|
|
|
|
|
|
|
if connErr != nil {
|
|
|
|
return false, connErr
|
|
|
|
}
|
|
|
|
|
|
|
|
return true, nil
|
|
|
|
}, func(err error) {
|
|
|
|
require.NoError(t, err)
|
|
|
|
})
|
2016-10-24 22:39:18 +00:00
|
|
|
}
|
|
|
|
|
2020-04-20 13:28:19 +00:00
|
|
|
func TestVaultClient_ValidateRole_NonExistent(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2017-05-16 16:59:58 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
2022-04-05 18:18:10 +00:00
|
|
|
v.Config.Token = defaultTestVaultAllowlistRoleAndToken(v, t, 5)
|
2017-05-16 16:59:58 +00:00
|
|
|
v.Config.Token = v.RootToken
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2017-05-16 16:59:58 +00:00
|
|
|
v.Config.ConnectionRetryIntv = 100 * time.Millisecond
|
2018-03-12 18:26:37 +00:00
|
|
|
v.Config.Role = "test-nonexistent"
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2017-05-16 16:59:58 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
// Wait for an error
|
|
|
|
var conn bool
|
|
|
|
var connErr error
|
|
|
|
testutil.WaitForResult(func() (bool, error) {
|
|
|
|
conn, connErr = client.ConnectionEstablished()
|
2018-03-09 02:27:49 +00:00
|
|
|
if !conn {
|
|
|
|
return false, fmt.Errorf("Should connect")
|
2017-05-16 16:59:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if connErr == nil {
|
|
|
|
return false, fmt.Errorf("expect an error")
|
|
|
|
}
|
|
|
|
|
|
|
|
return true, nil
|
|
|
|
}, func(err error) {
|
|
|
|
t.Fatalf("bad: %v", err)
|
|
|
|
})
|
|
|
|
|
|
|
|
errStr := connErr.Error()
|
|
|
|
if !strings.Contains(errStr, "does not exist") {
|
2018-03-15 22:32:08 +00:00
|
|
|
t.Fatalf("Expect does not exist error")
|
2017-05-16 16:59:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-22 01:33:35 +00:00
|
|
|
func TestVaultClient_ValidateToken(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2017-01-22 01:33:35 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
|
|
|
vaultPolicies := map[string]string{
|
|
|
|
"nomad-role-create": nomadRoleCreatePolicy,
|
|
|
|
"token-lookup": tokenLookupPolicy,
|
|
|
|
}
|
|
|
|
data := map[string]interface{}{
|
|
|
|
"allowed_policies": "token-lookup,nomad-role-create",
|
|
|
|
"period": 10,
|
|
|
|
}
|
|
|
|
v.Config.Token = testVaultRoleAndToken(v, t, vaultPolicies, data, []string{"token-lookup", "nomad-role-create"})
|
|
|
|
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2017-01-22 01:33:35 +00:00
|
|
|
v.Config.ConnectionRetryIntv = 100 * time.Millisecond
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2017-01-22 01:33:35 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
// Wait for an error
|
|
|
|
var conn bool
|
|
|
|
var connErr error
|
|
|
|
testutil.WaitForResult(func() (bool, error) {
|
|
|
|
conn, connErr = client.ConnectionEstablished()
|
2018-03-09 02:27:49 +00:00
|
|
|
if !conn {
|
|
|
|
return false, fmt.Errorf("Should connect")
|
2017-01-22 01:33:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if connErr == nil {
|
|
|
|
return false, fmt.Errorf("expect an error")
|
|
|
|
}
|
|
|
|
|
|
|
|
return true, nil
|
|
|
|
}, func(err error) {
|
|
|
|
t.Fatalf("bad: %v", err)
|
|
|
|
})
|
|
|
|
|
|
|
|
errStr := connErr.Error()
|
|
|
|
if !strings.Contains(errStr, vaultTokenRevokePath) {
|
2018-03-15 22:32:08 +00:00
|
|
|
t.Fatalf("Expect revoke error")
|
2017-01-22 01:33:35 +00:00
|
|
|
}
|
|
|
|
if !strings.Contains(errStr, fmt.Sprintf(vaultRoleLookupPath, "test")) {
|
|
|
|
t.Fatalf("Expect explicit max ttl error")
|
|
|
|
}
|
|
|
|
if !strings.Contains(errStr, "token must have one of the following") {
|
|
|
|
t.Fatalf("Expect explicit max ttl error")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-22 20:57:27 +00:00
|
|
|
func TestVaultClient_SetActive(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2016-08-22 20:57:27 +00:00
|
|
|
defer v.Stop()
|
2016-08-14 01:33:48 +00:00
|
|
|
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2016-08-22 20:57:27 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
waitForConnection(client, t)
|
|
|
|
|
|
|
|
// Do a lookup and expect an error about not being active
|
|
|
|
_, err = client.LookupToken(context.Background(), "123")
|
|
|
|
if err == nil || !strings.Contains(err.Error(), "not active") {
|
|
|
|
t.Fatalf("Expected not-active error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
client.SetActive(true)
|
|
|
|
|
|
|
|
// Do a lookup of ourselves
|
|
|
|
_, err = client.LookupToken(context.Background(), v.RootToken)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that we can update the config and things keep working
|
|
|
|
func TestVaultClient_SetConfig(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2016-08-22 20:57:27 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
2017-07-23 23:21:25 +00:00
|
|
|
v2 := testutil.NewTestVault(t)
|
2016-08-22 20:57:27 +00:00
|
|
|
defer v2.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
2022-04-05 18:18:10 +00:00
|
|
|
v2.Config.Token = defaultTestVaultAllowlistRoleAndToken(v2, t, 20)
|
2016-08-22 20:57:27 +00:00
|
|
|
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2016-08-22 20:57:27 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
waitForConnection(client, t)
|
|
|
|
|
|
|
|
if client.tokenData == nil || len(client.tokenData.Policies) != 1 {
|
|
|
|
t.Fatalf("unexpected token: %v", client.tokenData)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the config
|
|
|
|
if err := client.SetConfig(v2.Config); err != nil {
|
|
|
|
t.Fatalf("SetConfig failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
waitForConnection(client, t)
|
|
|
|
|
2017-01-22 01:33:35 +00:00
|
|
|
if client.tokenData == nil || len(client.tokenData.Policies) != 3 {
|
2016-08-22 20:57:27 +00:00
|
|
|
t.Fatalf("unexpected token: %v", client.tokenData)
|
2016-08-14 01:33:48 +00:00
|
|
|
}
|
2018-06-07 20:22:31 +00:00
|
|
|
|
2018-06-07 21:12:36 +00:00
|
|
|
// Test that when SetConfig is called with the same configuration, it is a
|
2018-06-07 20:22:31 +00:00
|
|
|
// no-op
|
|
|
|
failCh := make(chan struct{}, 1)
|
|
|
|
go func() {
|
|
|
|
tomb := client.tomb
|
|
|
|
select {
|
|
|
|
case <-tomb.Dying():
|
|
|
|
close(failCh)
|
|
|
|
case <-time.After(1 * time.Second):
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Update the config
|
|
|
|
if err := client.SetConfig(v2.Config); err != nil {
|
|
|
|
t.Fatalf("SetConfig failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-failCh:
|
|
|
|
t.Fatalf("Tomb shouldn't have exited")
|
|
|
|
case <-time.After(1 * time.Second):
|
|
|
|
return
|
|
|
|
}
|
2016-08-14 01:33:48 +00:00
|
|
|
}
|
|
|
|
|
2019-08-06 17:40:14 +00:00
|
|
|
// TestVaultClient_SetConfig_Deadlock asserts that calling SetConfig
|
|
|
|
// concurrently with establishConnection does not deadlock.
|
|
|
|
func TestVaultClient_SetConfig_Deadlock(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2019-08-06 17:40:14 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
v2 := testutil.NewTestVault(t)
|
|
|
|
defer v2.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
2022-04-05 18:18:10 +00:00
|
|
|
v2.Config.Token = defaultTestVaultAllowlistRoleAndToken(v2, t, 20)
|
2019-08-06 17:40:14 +00:00
|
|
|
|
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2019-08-06 17:40:14 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
for i := 0; i < 100; i++ {
|
|
|
|
// Alternate configs to cause updates
|
|
|
|
conf := v.Config
|
|
|
|
if i%2 == 0 {
|
|
|
|
conf = v2.Config
|
|
|
|
}
|
|
|
|
if err := client.SetConfig(conf); err != nil {
|
|
|
|
t.Fatalf("SetConfig failed: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-01 22:20:14 +00:00
|
|
|
// Test that we can disable vault
|
|
|
|
func TestVaultClient_SetConfig_Disable(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2017-02-01 22:20:14 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2017-02-01 22:20:14 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
waitForConnection(client, t)
|
|
|
|
|
|
|
|
if client.tokenData == nil || len(client.tokenData.Policies) != 1 {
|
|
|
|
t.Fatalf("unexpected token: %v", client.tokenData)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disable vault
|
|
|
|
f := false
|
|
|
|
config := config.VaultConfig{
|
|
|
|
Enabled: &f,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the config
|
|
|
|
if err := client.SetConfig(&config); err != nil {
|
|
|
|
t.Fatalf("SetConfig failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if client.Enabled() || client.Running() {
|
|
|
|
t.Fatalf("SetConfig should have stopped client")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-19 21:46:51 +00:00
|
|
|
func TestVaultClient_RenewalLoop(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2016-08-19 21:46:51 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
2022-04-05 18:18:10 +00:00
|
|
|
v.Config.Token = defaultTestVaultAllowlistRoleAndToken(v, t, 5)
|
2016-08-15 01:56:32 +00:00
|
|
|
|
|
|
|
// Start the client
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2016-08-15 01:56:32 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
// Sleep 8 seconds and ensure we have a non-zero TTL
|
|
|
|
time.Sleep(8 * time.Second)
|
|
|
|
|
|
|
|
// Get the current TTL
|
2016-08-19 21:46:51 +00:00
|
|
|
a := v.Client.Auth().Token()
|
2016-08-15 01:56:32 +00:00
|
|
|
s2, err := a.Lookup(v.Config.Token)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to lookup token: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ttl := parseTTLFromLookup(s2, t)
|
|
|
|
if ttl == 0 {
|
|
|
|
t.Fatalf("token renewal failed; ttl %v", ttl)
|
|
|
|
}
|
2018-11-09 16:34:09 +00:00
|
|
|
|
|
|
|
if client.currentExpiration.Before(time.Now()) {
|
|
|
|
t.Fatalf("found current expiration to be in past %s", time.Until(client.currentExpiration))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestVaultClientRenewUpdatesExpiration(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2018-11-09 16:34:09 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
2022-04-05 18:18:10 +00:00
|
|
|
v.Config.Token = defaultTestVaultAllowlistRoleAndToken(v, t, 5)
|
2018-11-09 16:34:09 +00:00
|
|
|
|
|
|
|
// Start the client
|
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2018-11-09 16:34:09 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
// Get the current TTL
|
|
|
|
a := v.Client.Auth().Token()
|
|
|
|
s2, err := a.Lookup(v.Config.Token)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to lookup token: %v", err)
|
|
|
|
}
|
|
|
|
exp0 := time.Now().Add(time.Duration(parseTTLFromLookup(s2, t)) * time.Second)
|
|
|
|
|
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
|
2018-11-20 20:14:57 +00:00
|
|
|
_, err = client.renew()
|
2018-11-09 16:34:09 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
exp1 := client.currentExpiration
|
|
|
|
require.True(t, exp0.Before(exp1))
|
|
|
|
|
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
|
2018-11-20 20:14:57 +00:00
|
|
|
_, err = client.renew()
|
2018-11-09 16:34:09 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
exp2 := client.currentExpiration
|
|
|
|
require.True(t, exp1.Before(exp2))
|
2016-08-15 01:56:32 +00:00
|
|
|
}
|
|
|
|
|
2018-11-20 20:14:57 +00:00
|
|
|
func TestVaultClient_StopsAfterPermissionError(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2018-11-20 20:14:57 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
2022-04-05 18:18:10 +00:00
|
|
|
v.Config.Token = defaultTestVaultAllowlistRoleAndToken(v, t, 2)
|
2018-11-20 20:14:57 +00:00
|
|
|
|
|
|
|
// Start the client
|
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2018-11-20 20:14:57 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
time.Sleep(500 * time.Millisecond)
|
|
|
|
|
|
|
|
assert.True(t, client.isRenewLoopActive())
|
|
|
|
|
|
|
|
// Get the current TTL
|
|
|
|
a := v.Client.Auth().Token()
|
|
|
|
assert.NoError(t, a.RevokeSelf(""))
|
|
|
|
|
|
|
|
testutil.WaitForResult(func() (bool, error) {
|
|
|
|
if !client.isRenewLoopActive() {
|
|
|
|
return true, nil
|
|
|
|
} else {
|
|
|
|
return false, errors.New("renew loop should terminate after token is revoked")
|
|
|
|
}
|
|
|
|
}, func(err error) {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
func TestVaultClient_LoopsUntilCannotRenew(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2018-11-20 20:14:57 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
2022-04-05 18:18:10 +00:00
|
|
|
v.Config.Token = defaultTestVaultAllowlistRoleAndToken(v, t, 5)
|
2018-11-20 20:14:57 +00:00
|
|
|
|
|
|
|
// Start the client
|
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2018-11-20 20:14:57 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
// Sleep 8 seconds and ensure we have a non-zero TTL
|
|
|
|
time.Sleep(8 * time.Second)
|
|
|
|
|
|
|
|
// Get the current TTL
|
|
|
|
a := v.Client.Auth().Token()
|
|
|
|
s2, err := a.Lookup(v.Config.Token)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to lookup token: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ttl := parseTTLFromLookup(s2, t)
|
|
|
|
if ttl == 0 {
|
|
|
|
t.Fatalf("token renewal failed; ttl %v", ttl)
|
|
|
|
}
|
|
|
|
|
|
|
|
if client.currentExpiration.Before(time.Now()) {
|
|
|
|
t.Fatalf("found current expiration to be in past %s", time.Until(client.currentExpiration))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-15 01:56:32 +00:00
|
|
|
func parseTTLFromLookup(s *vapi.Secret, t *testing.T) int64 {
|
|
|
|
if s == nil {
|
|
|
|
t.Fatalf("nil secret")
|
|
|
|
} else if s.Data == nil {
|
|
|
|
t.Fatalf("nil data block in secret")
|
|
|
|
}
|
|
|
|
|
|
|
|
ttlRaw, ok := s.Data["ttl"]
|
|
|
|
if !ok {
|
|
|
|
t.Fatalf("no ttl")
|
|
|
|
}
|
|
|
|
|
|
|
|
ttlNumber, ok := ttlRaw.(json.Number)
|
|
|
|
if !ok {
|
|
|
|
t.Fatalf("failed to convert ttl %q to json Number", ttlRaw)
|
|
|
|
}
|
|
|
|
|
|
|
|
ttl, err := ttlNumber.Int64()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to get ttl from json.Number: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ttl
|
2016-08-14 01:33:48 +00:00
|
|
|
}
|
2016-08-16 21:42:40 +00:00
|
|
|
|
|
|
|
func TestVaultClient_LookupToken_Invalid(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2016-10-11 20:28:18 +00:00
|
|
|
tr := true
|
2016-08-16 21:42:40 +00:00
|
|
|
conf := &config.VaultConfig{
|
2016-10-11 20:28:18 +00:00
|
|
|
Enabled: &tr,
|
2016-08-22 20:57:27 +00:00
|
|
|
Addr: "http://foobar:12345",
|
2017-09-29 16:58:48 +00:00
|
|
|
Token: uuid.Generate(),
|
2016-08-16 21:42:40 +00:00
|
|
|
}
|
|
|
|
|
2016-08-22 20:57:27 +00:00
|
|
|
// Enable vault but use a bad address so it never establishes a conn
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(conf, logger, nil, nil)
|
2016-08-16 21:42:40 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
2016-08-22 20:57:27 +00:00
|
|
|
client.SetActive(true)
|
2016-08-20 02:55:06 +00:00
|
|
|
defer client.Stop()
|
2016-08-16 21:42:40 +00:00
|
|
|
|
2016-08-18 20:52:15 +00:00
|
|
|
_, err = client.LookupToken(context.Background(), "foo")
|
2016-08-16 21:42:40 +00:00
|
|
|
if err == nil || !strings.Contains(err.Error(), "established") {
|
|
|
|
t.Fatalf("Expected error because connection to Vault hasn't been made: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-01 05:43:51 +00:00
|
|
|
func TestVaultClient_LookupToken_Root(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2016-08-16 21:42:40 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2016-08-16 21:42:40 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
2016-08-22 20:57:27 +00:00
|
|
|
client.SetActive(true)
|
2016-08-20 02:55:06 +00:00
|
|
|
defer client.Stop()
|
2016-08-16 21:42:40 +00:00
|
|
|
|
|
|
|
waitForConnection(client, t)
|
|
|
|
|
|
|
|
// Lookup ourselves
|
2016-08-18 20:52:15 +00:00
|
|
|
s, err := client.LookupToken(context.Background(), v.Config.Token)
|
2016-08-16 21:42:40 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("self lookup failed: %v", err)
|
|
|
|
}
|
|
|
|
|
2022-04-05 18:18:10 +00:00
|
|
|
policies, err := s.TokenPolicies()
|
2016-08-16 21:42:40 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to parse policies: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
expected := []string{"root"}
|
|
|
|
if !reflect.DeepEqual(policies, expected) {
|
|
|
|
t.Fatalf("Unexpected policies; got %v; want %v", policies, expected)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a token with a different set of policies
|
|
|
|
expected = []string{"default"}
|
|
|
|
req := vapi.TokenCreateRequest{
|
|
|
|
Policies: expected,
|
|
|
|
}
|
|
|
|
s, err = v.Client.Auth().Token().Create(&req)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to create child token: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the client token
|
|
|
|
if s == nil || s.Auth == nil {
|
|
|
|
t.Fatalf("bad secret response: %+v", s)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup new child
|
2016-08-18 20:52:15 +00:00
|
|
|
s, err = client.LookupToken(context.Background(), s.Auth.ClientToken)
|
2016-08-16 21:42:40 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("self lookup failed: %v", err)
|
|
|
|
}
|
|
|
|
|
2022-04-05 18:18:10 +00:00
|
|
|
policies, err = s.TokenPolicies()
|
2016-08-16 21:42:40 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to parse policies: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(policies, expected) {
|
|
|
|
t.Fatalf("Unexpected policies; got %v; want %v", policies, expected)
|
|
|
|
}
|
|
|
|
}
|
2016-08-18 20:52:15 +00:00
|
|
|
|
2016-11-01 05:43:51 +00:00
|
|
|
func TestVaultClient_LookupToken_Role(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2016-11-01 05:43:51 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
2022-04-05 18:18:10 +00:00
|
|
|
v.Config.Token = defaultTestVaultAllowlistRoleAndToken(v, t, 5)
|
2016-11-01 05:43:51 +00:00
|
|
|
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2016-11-01 05:43:51 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
client.SetActive(true)
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
waitForConnection(client, t)
|
|
|
|
|
|
|
|
// Lookup ourselves
|
|
|
|
s, err := client.LookupToken(context.Background(), v.Config.Token)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("self lookup failed: %v", err)
|
|
|
|
}
|
|
|
|
|
2022-04-05 18:18:10 +00:00
|
|
|
policies, err := s.TokenPolicies()
|
2016-11-01 05:43:51 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to parse policies: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-01-22 01:33:35 +00:00
|
|
|
expected := []string{"default", "nomad-role-create", "nomad-role-management"}
|
2016-11-01 05:43:51 +00:00
|
|
|
if !reflect.DeepEqual(policies, expected) {
|
|
|
|
t.Fatalf("Unexpected policies; got %v; want %v", policies, expected)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a token with a different set of policies
|
|
|
|
expected = []string{"default"}
|
|
|
|
req := vapi.TokenCreateRequest{
|
|
|
|
Policies: expected,
|
|
|
|
}
|
|
|
|
s, err = v.Client.Auth().Token().Create(&req)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to create child token: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the client token
|
|
|
|
if s == nil || s.Auth == nil {
|
|
|
|
t.Fatalf("bad secret response: %+v", s)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup new child
|
|
|
|
s, err = client.LookupToken(context.Background(), s.Auth.ClientToken)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("self lookup failed: %v", err)
|
|
|
|
}
|
|
|
|
|
2022-04-05 18:18:10 +00:00
|
|
|
policies, err = s.TokenPolicies()
|
2016-11-01 05:43:51 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to parse policies: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(policies, expected) {
|
|
|
|
t.Fatalf("Unexpected policies; got %v; want %v", policies, expected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-18 20:52:15 +00:00
|
|
|
func TestVaultClient_LookupToken_RateLimit(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2016-08-18 20:52:15 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2016-08-18 20:52:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
2016-08-22 20:57:27 +00:00
|
|
|
client.SetActive(true)
|
2016-08-20 02:55:06 +00:00
|
|
|
defer client.Stop()
|
2016-08-18 20:52:15 +00:00
|
|
|
|
|
|
|
waitForConnection(client, t)
|
|
|
|
|
2017-10-20 00:29:10 +00:00
|
|
|
client.setLimit(rate.Limit(1.0))
|
2022-04-05 18:18:10 +00:00
|
|
|
testRateLimit(t, 20, client, func(ctx context.Context) error {
|
|
|
|
// Lookup ourselves
|
|
|
|
_, err := client.LookupToken(ctx, v.Config.Token)
|
|
|
|
return err
|
|
|
|
})
|
|
|
|
}
|
2017-10-20 00:29:10 +00:00
|
|
|
|
2016-08-19 21:46:51 +00:00
|
|
|
func TestVaultClient_CreateToken_Root(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2016-08-19 21:46:51 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2016-08-19 21:46:51 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
2016-08-22 20:57:27 +00:00
|
|
|
client.SetActive(true)
|
2016-08-20 02:55:06 +00:00
|
|
|
defer client.Stop()
|
2016-08-19 21:46:51 +00:00
|
|
|
|
|
|
|
waitForConnection(client, t)
|
|
|
|
|
|
|
|
// Create an allocation that requires a Vault policy
|
|
|
|
a := mock.Alloc()
|
|
|
|
task := a.Job.TaskGroups[0].Tasks[0]
|
|
|
|
task.Vault = &structs.Vault{Policies: []string{"default"}}
|
|
|
|
|
|
|
|
s, err := client.CreateToken(context.Background(), a, task.Name)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("CreateToken failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that created secret is a wrapped token
|
|
|
|
if s == nil || s.WrapInfo == nil {
|
|
|
|
t.Fatalf("Bad secret: %#v", s)
|
|
|
|
}
|
|
|
|
|
|
|
|
d, err := time.ParseDuration(vaultTokenCreateTTL)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("bad: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.WrapInfo.WrappedAccessor == "" {
|
|
|
|
t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor)
|
|
|
|
} else if s.WrapInfo.Token == "" {
|
|
|
|
t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor)
|
|
|
|
} else if s.WrapInfo.TTL != int(d.Seconds()) {
|
|
|
|
t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-05 18:18:10 +00:00
|
|
|
func TestVaultClient_CreateToken_Allowlist_Role(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2022-04-05 18:18:10 +00:00
|
|
|
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2016-08-19 21:46:51 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
2022-04-05 18:18:10 +00:00
|
|
|
v.Config.Token = defaultTestVaultAllowlistRoleAndToken(v, t, 5)
|
2016-10-23 01:08:30 +00:00
|
|
|
|
2016-08-19 21:46:51 +00:00
|
|
|
// Start the client
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2016-08-19 21:46:51 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
2016-08-22 20:57:27 +00:00
|
|
|
client.SetActive(true)
|
2016-08-19 21:46:51 +00:00
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
waitForConnection(client, t)
|
|
|
|
|
|
|
|
// Create an allocation that requires a Vault policy
|
|
|
|
a := mock.Alloc()
|
|
|
|
task := a.Job.TaskGroups[0].Tasks[0]
|
|
|
|
task.Vault = &structs.Vault{Policies: []string{"default"}}
|
|
|
|
|
|
|
|
s, err := client.CreateToken(context.Background(), a, task.Name)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("CreateToken failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that created secret is a wrapped token
|
|
|
|
if s == nil || s.WrapInfo == nil {
|
|
|
|
t.Fatalf("Bad secret: %#v", s)
|
|
|
|
}
|
|
|
|
|
|
|
|
d, err := time.ParseDuration(vaultTokenCreateTTL)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("bad: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.WrapInfo.WrappedAccessor == "" {
|
|
|
|
t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor)
|
|
|
|
} else if s.WrapInfo.Token == "" {
|
|
|
|
t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor)
|
|
|
|
} else if s.WrapInfo.TTL != int(d.Seconds()) {
|
|
|
|
t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor)
|
|
|
|
}
|
|
|
|
}
|
2016-08-22 20:57:27 +00:00
|
|
|
|
2017-01-22 01:33:35 +00:00
|
|
|
func TestVaultClient_CreateToken_Root_Target_Role(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2017-01-22 01:33:35 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Create the test role
|
2022-04-05 18:18:10 +00:00
|
|
|
defaultTestVaultAllowlistRoleAndToken(v, t, 5)
|
2017-01-22 01:33:35 +00:00
|
|
|
|
|
|
|
// Target the test role
|
|
|
|
v.Config.Role = "test"
|
|
|
|
|
|
|
|
// Start the client
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2017-01-22 01:33:35 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
client.SetActive(true)
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
waitForConnection(client, t)
|
|
|
|
|
|
|
|
// Create an allocation that requires a Vault policy
|
|
|
|
a := mock.Alloc()
|
|
|
|
task := a.Job.TaskGroups[0].Tasks[0]
|
|
|
|
task.Vault = &structs.Vault{Policies: []string{"default"}}
|
|
|
|
|
|
|
|
s, err := client.CreateToken(context.Background(), a, task.Name)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("CreateToken failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that created secret is a wrapped token
|
|
|
|
if s == nil || s.WrapInfo == nil {
|
|
|
|
t.Fatalf("Bad secret: %#v", s)
|
|
|
|
}
|
|
|
|
|
|
|
|
d, err := time.ParseDuration(vaultTokenCreateTTL)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("bad: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.WrapInfo.WrappedAccessor == "" {
|
|
|
|
t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor)
|
|
|
|
} else if s.WrapInfo.Token == "" {
|
|
|
|
t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor)
|
|
|
|
} else if s.WrapInfo.TTL != int(d.Seconds()) {
|
|
|
|
t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-05 18:18:10 +00:00
|
|
|
func TestVaultClient_CreateToken_Denylist_Role(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2022-04-05 18:18:10 +00:00
|
|
|
|
2017-01-27 23:06:01 +00:00
|
|
|
// Need to skip if test is 0.6.4
|
|
|
|
version, err := testutil.VaultVersion()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to determine version: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.Contains(version, "v0.6.4") {
|
2017-01-27 23:19:22 +00:00
|
|
|
t.Skipf("Vault has a regression in v0.6.4 that this test hits")
|
2017-01-27 23:06:01 +00:00
|
|
|
}
|
|
|
|
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2017-01-22 01:33:35 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
2022-04-05 18:18:10 +00:00
|
|
|
v.Config.Token = defaultTestVaultDenylistRoleAndToken(v, t, 5)
|
2017-01-23 18:40:28 +00:00
|
|
|
v.Config.Role = "test"
|
2017-01-22 01:33:35 +00:00
|
|
|
|
|
|
|
// Start the client
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2017-01-22 01:33:35 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
client.SetActive(true)
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
waitForConnection(client, t)
|
|
|
|
|
|
|
|
// Create an allocation that requires a Vault policy
|
|
|
|
a := mock.Alloc()
|
|
|
|
task := a.Job.TaskGroups[0].Tasks[0]
|
|
|
|
task.Vault = &structs.Vault{Policies: []string{"secrets"}}
|
|
|
|
|
|
|
|
s, err := client.CreateToken(context.Background(), a, task.Name)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("CreateToken failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that created secret is a wrapped token
|
|
|
|
if s == nil || s.WrapInfo == nil {
|
|
|
|
t.Fatalf("Bad secret: %#v", s)
|
|
|
|
}
|
|
|
|
|
|
|
|
d, err := time.ParseDuration(vaultTokenCreateTTL)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("bad: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.WrapInfo.WrappedAccessor == "" {
|
|
|
|
t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor)
|
|
|
|
} else if s.WrapInfo.Token == "" {
|
|
|
|
t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor)
|
|
|
|
} else if s.WrapInfo.TTL != int(d.Seconds()) {
|
|
|
|
t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-23 01:08:30 +00:00
|
|
|
func TestVaultClient_CreateToken_Role_InvalidToken(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2016-10-23 01:08:30 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
2022-04-05 18:18:10 +00:00
|
|
|
defaultTestVaultAllowlistRoleAndToken(v, t, 5)
|
2016-10-23 01:08:30 +00:00
|
|
|
v.Config.Token = "foo-bar"
|
|
|
|
|
|
|
|
// Start the client
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2016-10-23 01:08:30 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
client.SetActive(true)
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
testutil.WaitForResult(func() (bool, error) {
|
|
|
|
established, err := client.ConnectionEstablished()
|
2018-03-09 02:27:49 +00:00
|
|
|
if !established {
|
|
|
|
return false, fmt.Errorf("Should establish")
|
2016-10-23 01:08:30 +00:00
|
|
|
}
|
|
|
|
return err != nil, nil
|
|
|
|
}, func(err error) {
|
|
|
|
t.Fatalf("Connection not established")
|
|
|
|
})
|
|
|
|
|
|
|
|
// Create an allocation that requires a Vault policy
|
|
|
|
a := mock.Alloc()
|
|
|
|
task := a.Job.TaskGroups[0].Tasks[0]
|
|
|
|
task.Vault = &structs.Vault{Policies: []string{"default"}}
|
|
|
|
|
|
|
|
_, err = client.CreateToken(context.Background(), a, task.Name)
|
2019-01-23 13:03:11 +00:00
|
|
|
if err == nil || !strings.Contains(err.Error(), "failed to establish connection to Vault") {
|
2016-10-23 01:08:30 +00:00
|
|
|
t.Fatalf("CreateToken should have failed: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-08 18:38:54 +00:00
|
|
|
func TestVaultClient_CreateToken_Role_Unrecoverable(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2016-11-08 18:38:54 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
2022-04-05 18:18:10 +00:00
|
|
|
v.Config.Token = defaultTestVaultAllowlistRoleAndToken(v, t, 5)
|
2016-11-08 18:38:54 +00:00
|
|
|
|
|
|
|
// Start the client
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, nil, nil)
|
2016-11-08 18:38:54 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
client.SetActive(true)
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
waitForConnection(client, t)
|
|
|
|
|
|
|
|
// Create an allocation that requires a Vault policy
|
|
|
|
a := mock.Alloc()
|
|
|
|
task := a.Job.TaskGroups[0].Tasks[0]
|
|
|
|
task.Vault = &structs.Vault{Policies: []string{"unknown_policy"}}
|
|
|
|
|
|
|
|
_, err = client.CreateToken(context.Background(), a, task.Name)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("CreateToken should have failed: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-03-24 22:26:05 +00:00
|
|
|
_, ok := err.(structs.Recoverable)
|
2016-11-08 19:04:11 +00:00
|
|
|
if ok {
|
2017-03-24 22:26:05 +00:00
|
|
|
t.Fatalf("CreateToken should not be a recoverable error type: %v (%T)", err, err)
|
2016-11-08 18:38:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-23 01:08:30 +00:00
|
|
|
func TestVaultClient_CreateToken_Prestart(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
vconfig := &config.VaultConfig{
|
2022-08-17 16:26:34 +00:00
|
|
|
Enabled: pointer.Of(true),
|
2017-09-29 16:58:48 +00:00
|
|
|
Token: uuid.Generate(),
|
2017-07-23 23:21:25 +00:00
|
|
|
Addr: "http://127.0.0.1:0",
|
|
|
|
}
|
2016-10-23 01:08:30 +00:00
|
|
|
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(vconfig, logger, nil, nil)
|
2016-10-23 01:08:30 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
client.SetActive(true)
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
// Create an allocation that requires a Vault policy
|
|
|
|
a := mock.Alloc()
|
|
|
|
task := a.Job.TaskGroups[0].Tasks[0]
|
|
|
|
task.Vault = &structs.Vault{Policies: []string{"default"}}
|
|
|
|
|
|
|
|
_, err = client.CreateToken(context.Background(), a, task.Name)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("CreateToken should have failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if rerr, ok := err.(*structs.RecoverableError); !ok {
|
|
|
|
t.Fatalf("Err should have been type recoverable error")
|
2017-03-27 23:27:24 +00:00
|
|
|
} else if ok && !rerr.IsRecoverable() {
|
2016-10-23 01:08:30 +00:00
|
|
|
t.Fatalf("Err should have been recoverable")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-21 11:38:27 +00:00
|
|
|
func TestVaultClient_MarkForRevocation(t *testing.T) {
|
|
|
|
vconfig := &config.VaultConfig{
|
2022-08-17 16:26:34 +00:00
|
|
|
Enabled: pointer.Of(true),
|
2020-05-21 11:38:27 +00:00
|
|
|
Token: uuid.Generate(),
|
|
|
|
Addr: "http://127.0.0.1:0",
|
|
|
|
}
|
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(vconfig, logger, nil, nil)
|
2020-05-21 11:38:27 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
client.SetActive(true)
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
// Create some VaultAccessors
|
|
|
|
vas := []*structs.VaultAccessor{
|
|
|
|
mock.VaultAccessor(),
|
|
|
|
mock.VaultAccessor(),
|
|
|
|
}
|
|
|
|
|
|
|
|
err = client.MarkForRevocation(vas)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Wasn't committed
|
|
|
|
require.Len(t, client.revoking, 2)
|
|
|
|
require.Equal(t, 2, client.stats().TrackedForRevoke)
|
|
|
|
|
|
|
|
}
|
2016-08-22 20:57:27 +00:00
|
|
|
func TestVaultClient_RevokeTokens_PreEstablishs(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
vconfig := &config.VaultConfig{
|
2022-08-17 16:26:34 +00:00
|
|
|
Enabled: pointer.Of(true),
|
2017-09-29 16:58:48 +00:00
|
|
|
Token: uuid.Generate(),
|
2017-07-23 23:21:25 +00:00
|
|
|
Addr: "http://127.0.0.1:0",
|
|
|
|
}
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(vconfig, logger, nil, nil)
|
2016-08-22 20:57:27 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
client.SetActive(true)
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
// Create some VaultAccessors
|
|
|
|
vas := []*structs.VaultAccessor{
|
|
|
|
mock.VaultAccessor(),
|
|
|
|
mock.VaultAccessor(),
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := client.RevokeTokens(context.Background(), vas, false); err != nil {
|
|
|
|
t.Fatalf("RevokeTokens failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wasn't committed
|
|
|
|
if len(client.revoking) != 0 {
|
|
|
|
t.Fatalf("didn't add to revoke loop")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := client.RevokeTokens(context.Background(), vas, true); err != nil {
|
|
|
|
t.Fatalf("RevokeTokens failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Was committed
|
|
|
|
if len(client.revoking) != 2 {
|
|
|
|
t.Fatalf("didn't add to revoke loop")
|
|
|
|
}
|
2017-02-15 00:02:18 +00:00
|
|
|
|
2018-11-09 16:34:09 +00:00
|
|
|
if client.stats().TrackedForRevoke != 2 {
|
2017-02-15 00:02:18 +00:00
|
|
|
t.Fatalf("didn't add to revoke loop")
|
|
|
|
}
|
2016-08-22 20:57:27 +00:00
|
|
|
}
|
|
|
|
|
2020-07-28 21:59:16 +00:00
|
|
|
// TestVaultClient_RevokeTokens_Failures_TTL asserts that
|
2020-05-14 14:56:58 +00:00
|
|
|
// the registered TTL doesn't get extended on retries
|
|
|
|
func TestVaultClient_RevokeTokens_Failures_TTL(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2020-05-14 14:56:58 +00:00
|
|
|
vconfig := &config.VaultConfig{
|
2022-08-17 16:26:34 +00:00
|
|
|
Enabled: pointer.Of(true),
|
2020-05-14 14:56:58 +00:00
|
|
|
Token: uuid.Generate(),
|
|
|
|
Addr: "http://127.0.0.1:0",
|
|
|
|
}
|
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(vconfig, logger, nil, nil)
|
2020-05-14 14:56:58 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
client.SetActive(true)
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
// Create some VaultAccessors
|
|
|
|
vas := []*structs.VaultAccessor{
|
|
|
|
mock.VaultAccessor(),
|
|
|
|
mock.VaultAccessor(),
|
|
|
|
}
|
|
|
|
|
|
|
|
err = client.RevokeTokens(context.Background(), vas, true)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Was committed
|
|
|
|
require.Len(t, client.revoking, 2)
|
|
|
|
|
|
|
|
// set TTL
|
|
|
|
ttl := time.Now().Add(50 * time.Second)
|
|
|
|
client.revoking[vas[0]] = ttl
|
|
|
|
client.revoking[vas[1]] = ttl
|
|
|
|
|
|
|
|
// revoke again and ensure that TTL isn't extended
|
|
|
|
err = client.RevokeTokens(context.Background(), vas, true)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.Len(t, client.revoking, 2)
|
|
|
|
expected := map[*structs.VaultAccessor]time.Time{
|
|
|
|
vas[0]: ttl,
|
|
|
|
vas[1]: ttl,
|
|
|
|
}
|
|
|
|
require.Equal(t, expected, client.revoking)
|
|
|
|
}
|
|
|
|
|
2016-11-01 05:43:51 +00:00
|
|
|
func TestVaultClient_RevokeTokens_Root(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2016-08-22 20:57:27 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
purged := 0
|
|
|
|
purge := func(accessors []*structs.VaultAccessor) error {
|
|
|
|
purged += len(accessors)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, purge, nil)
|
2016-08-22 20:57:27 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
client.SetActive(true)
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
waitForConnection(client, t)
|
|
|
|
|
2016-11-01 05:43:51 +00:00
|
|
|
// Create some vault tokens
|
|
|
|
auth := v.Client.Auth().Token()
|
|
|
|
req := vapi.TokenCreateRequest{
|
|
|
|
Policies: []string{"default"},
|
|
|
|
}
|
|
|
|
t1, err := auth.Create(&req)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to create vault token: %v", err)
|
|
|
|
}
|
|
|
|
if t1 == nil || t1.Auth == nil {
|
|
|
|
t.Fatalf("bad secret response: %+v", t1)
|
|
|
|
}
|
|
|
|
t2, err := auth.Create(&req)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to create vault token: %v", err)
|
|
|
|
}
|
|
|
|
if t2 == nil || t2.Auth == nil {
|
|
|
|
t.Fatalf("bad secret response: %+v", t2)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create two VaultAccessors
|
|
|
|
vas := []*structs.VaultAccessor{
|
2017-09-26 22:26:33 +00:00
|
|
|
{Accessor: t1.Auth.Accessor},
|
|
|
|
{Accessor: t2.Auth.Accessor},
|
2016-11-01 05:43:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Issue a token revocation
|
|
|
|
if err := client.RevokeTokens(context.Background(), vas, true); err != nil {
|
|
|
|
t.Fatalf("RevokeTokens failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup the token and make sure we get an error
|
|
|
|
if s, err := auth.Lookup(t1.Auth.ClientToken); err == nil {
|
|
|
|
t.Fatalf("Revoked token lookup didn't fail: %+v", s)
|
|
|
|
}
|
|
|
|
if s, err := auth.Lookup(t2.Auth.ClientToken); err == nil {
|
|
|
|
t.Fatalf("Revoked token lookup didn't fail: %+v", s)
|
|
|
|
}
|
|
|
|
|
|
|
|
if purged != 2 {
|
|
|
|
t.Fatalf("Expected purged 2; got %d", purged)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestVaultClient_RevokeTokens_Role(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-07-23 23:21:25 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
2016-11-01 05:43:51 +00:00
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
2022-04-05 18:18:10 +00:00
|
|
|
v.Config.Token = defaultTestVaultAllowlistRoleAndToken(v, t, 5)
|
2016-11-01 05:43:51 +00:00
|
|
|
|
|
|
|
purged := 0
|
|
|
|
purge := func(accessors []*structs.VaultAccessor) error {
|
|
|
|
purged += len(accessors)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-09-15 23:23:13 +00:00
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, purge, nil)
|
2016-11-01 05:43:51 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
client.SetActive(true)
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
waitForConnection(client, t)
|
|
|
|
|
2016-08-22 20:57:27 +00:00
|
|
|
// Create some vault tokens
|
|
|
|
auth := v.Client.Auth().Token()
|
|
|
|
req := vapi.TokenCreateRequest{
|
|
|
|
Policies: []string{"default"},
|
|
|
|
}
|
|
|
|
t1, err := auth.Create(&req)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to create vault token: %v", err)
|
|
|
|
}
|
|
|
|
if t1 == nil || t1.Auth == nil {
|
|
|
|
t.Fatalf("bad secret response: %+v", t1)
|
|
|
|
}
|
|
|
|
t2, err := auth.Create(&req)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to create vault token: %v", err)
|
|
|
|
}
|
|
|
|
if t2 == nil || t2.Auth == nil {
|
|
|
|
t.Fatalf("bad secret response: %+v", t2)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create two VaultAccessors
|
|
|
|
vas := []*structs.VaultAccessor{
|
2017-09-26 22:26:33 +00:00
|
|
|
{Accessor: t1.Auth.Accessor},
|
|
|
|
{Accessor: t2.Auth.Accessor},
|
2016-08-22 20:57:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Issue a token revocation
|
|
|
|
if err := client.RevokeTokens(context.Background(), vas, true); err != nil {
|
|
|
|
t.Fatalf("RevokeTokens failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup the token and make sure we get an error
|
2017-01-20 18:06:47 +00:00
|
|
|
if purged != 2 {
|
|
|
|
t.Fatalf("Expected purged 2; got %d", purged)
|
|
|
|
}
|
2016-08-22 20:57:27 +00:00
|
|
|
if s, err := auth.Lookup(t1.Auth.ClientToken); err == nil {
|
|
|
|
t.Fatalf("Revoked token lookup didn't fail: %+v", s)
|
|
|
|
}
|
|
|
|
if s, err := auth.Lookup(t2.Auth.ClientToken); err == nil {
|
|
|
|
t.Fatalf("Revoked token lookup didn't fail: %+v", s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-14 14:56:58 +00:00
|
|
|
// TestVaultClient_RevokeTokens_Idempotent asserts that token revocation
|
|
|
|
// is idempotent, and can cope with cases if token was deleted out of band.
|
|
|
|
func TestVaultClient_RevokeTokens_Idempotent(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2020-05-14 14:56:58 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
2022-04-05 18:18:10 +00:00
|
|
|
v.Config.Token = defaultTestVaultAllowlistRoleAndToken(v, t, 5)
|
2020-05-14 14:56:58 +00:00
|
|
|
|
|
|
|
purged := map[string]struct{}{}
|
|
|
|
purge := func(accessors []*structs.VaultAccessor) error {
|
|
|
|
for _, accessor := range accessors {
|
|
|
|
purged[accessor.Accessor] = struct{}{}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
logger := testlog.HCLogger(t)
|
2020-07-17 14:41:45 +00:00
|
|
|
client, err := NewVaultClient(v.Config, logger, purge, nil)
|
2020-05-14 14:56:58 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to build vault client: %v", err)
|
|
|
|
}
|
|
|
|
client.SetActive(true)
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
waitForConnection(client, t)
|
|
|
|
|
|
|
|
// Create some vault tokens
|
|
|
|
auth := v.Client.Auth().Token()
|
|
|
|
req := vapi.TokenCreateRequest{
|
|
|
|
Policies: []string{"default"},
|
|
|
|
}
|
|
|
|
t1, err := auth.Create(&req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, t1)
|
|
|
|
require.NotNil(t, t1.Auth)
|
|
|
|
|
|
|
|
t2, err := auth.Create(&req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, t2)
|
|
|
|
require.NotNil(t, t2.Auth)
|
|
|
|
|
|
|
|
t3, err := auth.Create(&req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, t3)
|
|
|
|
require.NotNil(t, t3.Auth)
|
|
|
|
|
|
|
|
// revoke t3 out of band
|
|
|
|
err = auth.RevokeAccessor(t3.Auth.Accessor)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Create two VaultAccessors
|
|
|
|
vas := []*structs.VaultAccessor{
|
|
|
|
{Accessor: t1.Auth.Accessor},
|
|
|
|
{Accessor: t2.Auth.Accessor},
|
|
|
|
{Accessor: t3.Auth.Accessor},
|
|
|
|
}
|
|
|
|
|
|
|
|
// Issue a token revocation
|
|
|
|
err = client.RevokeTokens(context.Background(), vas, true)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Empty(t, client.revoking)
|
|
|
|
|
|
|
|
// revoke token again
|
|
|
|
err = client.RevokeTokens(context.Background(), vas, true)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Empty(t, client.revoking)
|
|
|
|
|
|
|
|
// Lookup the token and make sure we get an error
|
|
|
|
require.Len(t, purged, 3)
|
|
|
|
require.Contains(t, purged, t1.Auth.Accessor)
|
|
|
|
require.Contains(t, purged, t2.Auth.Accessor)
|
|
|
|
require.Contains(t, purged, t3.Auth.Accessor)
|
|
|
|
s, err := auth.Lookup(t1.Auth.ClientToken)
|
|
|
|
require.Errorf(t, err, "failed to purge token: %v", s)
|
|
|
|
s, err = auth.Lookup(t2.Auth.ClientToken)
|
|
|
|
require.Errorf(t, err, "failed to purge token: %v", s)
|
|
|
|
}
|
|
|
|
|
2020-07-28 21:59:16 +00:00
|
|
|
// TestVaultClient_RevokeDaemon_Bounded asserts that token revocation
|
|
|
|
// batches are bounded in size.
|
|
|
|
func TestVaultClient_RevokeDaemon_Bounded(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2020-07-28 21:59:16 +00:00
|
|
|
v := testutil.NewTestVault(t)
|
|
|
|
defer v.Stop()
|
|
|
|
|
|
|
|
// Set the configs token in a new test role
|
2022-04-05 18:18:10 +00:00
|
|
|
v.Config.Token = defaultTestVaultAllowlistRoleAndToken(v, t, 5)
|
2020-07-28 21:59:16 +00:00
|
|
|
|
|
|
|
// Disable client until we can change settings for testing
|
|
|
|
conf := v.Config.Copy()
|
2022-08-17 16:26:34 +00:00
|
|
|
conf.Enabled = pointer.Of(false)
|
2020-07-28 21:59:16 +00:00
|
|
|
|
|
|
|
const (
|
|
|
|
batchSize = 100
|
|
|
|
batches = 3
|
|
|
|
)
|
|
|
|
resultCh := make(chan error, batches)
|
|
|
|
var totalPurges int64
|
|
|
|
|
|
|
|
// Purge function asserts batches are always < batchSize
|
|
|
|
purge := func(vas []*structs.VaultAccessor) error {
|
|
|
|
if len(vas) > batchSize {
|
|
|
|
resultCh <- fmt.Errorf("too many Vault accessors in batch: %d > %d", len(vas), batchSize)
|
|
|
|
} else {
|
|
|
|
resultCh <- nil
|
|
|
|
}
|
|
|
|
atomic.AddInt64(&totalPurges, int64(len(vas)))
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
logger := testlog.HCLogger(t)
|
|
|
|
client, err := NewVaultClient(conf, logger, purge, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Override settings for testing and then enable client
|
|
|
|
client.maxRevokeBatchSize = batchSize
|
|
|
|
client.revocationIntv = 3 * time.Millisecond
|
|
|
|
conf = v.Config.Copy()
|
2022-08-17 16:26:34 +00:00
|
|
|
conf.Enabled = pointer.Of(true)
|
2020-07-28 21:59:16 +00:00
|
|
|
require.NoError(t, client.SetConfig(conf))
|
|
|
|
|
|
|
|
client.SetActive(true)
|
|
|
|
defer client.Stop()
|
|
|
|
|
|
|
|
waitForConnection(client, t)
|
|
|
|
|
|
|
|
// Create more tokens in Nomad than can fit in a batch; they don't need
|
|
|
|
// to exist in Vault.
|
|
|
|
accessors := make([]*structs.VaultAccessor, batchSize*batches)
|
|
|
|
for i := 0; i < len(accessors); i++ {
|
|
|
|
accessors[i] = &structs.VaultAccessor{Accessor: "abcd"}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mark for revocation
|
|
|
|
require.NoError(t, client.MarkForRevocation(accessors))
|
|
|
|
|
|
|
|
// Wait for tokens to be revoked
|
|
|
|
for i := 0; i < batches; i++ {
|
|
|
|
select {
|
|
|
|
case err := <-resultCh:
|
|
|
|
require.NoError(t, err)
|
|
|
|
case <-time.After(10 * time.Second):
|
|
|
|
// 10 seconds should be plenty long to process 3
|
|
|
|
// batches at a 3ms tick interval!
|
|
|
|
t.Errorf("timed out processing %d batches. %d/%d complete in 10s",
|
|
|
|
batches, i, batches)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
require.Equal(t, int64(len(accessors)), atomic.LoadInt64(&totalPurges))
|
|
|
|
}
|
|
|
|
|
2016-08-22 20:57:27 +00:00
|
|
|
func waitForConnection(v *vaultClient, t *testing.T) {
|
|
|
|
testutil.WaitForResult(func() (bool, error) {
|
2016-10-23 01:08:30 +00:00
|
|
|
return v.ConnectionEstablished()
|
2016-08-22 20:57:27 +00:00
|
|
|
}, func(err error) {
|
|
|
|
t.Fatalf("Connection not established")
|
|
|
|
})
|
|
|
|
}
|
2018-10-30 14:19:25 +00:00
|
|
|
|
|
|
|
func TestVaultClient_nextBackoff(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
|
|
|
|
2018-10-30 14:19:25 +00:00
|
|
|
simpleCases := []struct {
|
|
|
|
name string
|
|
|
|
initBackoff float64
|
|
|
|
|
|
|
|
// define range of acceptable backoff values accounting for random factor
|
|
|
|
rangeMin float64
|
|
|
|
rangeMax float64
|
|
|
|
}{
|
|
|
|
{"simple case", 7.0, 8.7, 17.60},
|
|
|
|
{"too low", 2.0, 5.0, 10.0},
|
|
|
|
{"too large", 100, 30.0, 60.0},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range simpleCases {
|
|
|
|
t.Run(c.name, func(t *testing.T) {
|
|
|
|
b := nextBackoff(c.initBackoff, time.Now().Add(10*time.Hour))
|
|
|
|
if !(c.rangeMin <= b && b <= c.rangeMax) {
|
|
|
|
t.Fatalf("Expected backoff within [%v, %v] but found %v", c.rangeMin, c.rangeMax, b)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// some edge cases
|
|
|
|
t.Run("close to expiry", func(t *testing.T) {
|
|
|
|
b := nextBackoff(20, time.Now().Add(1100*time.Millisecond))
|
2018-11-01 12:40:28 +00:00
|
|
|
if b != 5.0 {
|
|
|
|
t.Fatalf("Expected backoff is 5 but found %v", b)
|
2018-10-30 14:19:25 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("past expiry", func(t *testing.T) {
|
|
|
|
b := nextBackoff(20, time.Now().Add(-1100*time.Millisecond))
|
2018-11-20 20:14:57 +00:00
|
|
|
if !(60 <= b && b <= 120) {
|
|
|
|
t.Fatalf("Expected backoff within [%v, %v] but found %v", 60, 120, b)
|
2018-10-30 14:19:25 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2022-04-05 18:18:10 +00:00
|
|
|
|
|
|
|
func testRateLimit(t *testing.T, count int, client *vaultClient, fn func(context.Context) error) {
|
|
|
|
// Spin up many requests. These should block
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
cancels := 0
|
|
|
|
unblock := make(chan struct{})
|
|
|
|
for i := 0; i < count; i++ {
|
|
|
|
go func() {
|
|
|
|
err := fn(ctx)
|
|
|
|
if err != nil {
|
|
|
|
if err == context.Canceled {
|
|
|
|
cancels += 1
|
|
|
|
return
|
|
|
|
}
|
|
|
|
t.Errorf("request failed: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cancel the context
|
|
|
|
close(unblock)
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-time.After(5 * time.Second):
|
|
|
|
t.Fatalf("timeout")
|
|
|
|
case <-unblock:
|
|
|
|
cancel()
|
|
|
|
}
|
|
|
|
|
|
|
|
desired := count - 1
|
|
|
|
testutil.WaitForResult(func() (bool, error) {
|
|
|
|
if desired-cancels > 2 {
|
|
|
|
return false, fmt.Errorf("Incorrect number of cancels; got %d; want %d", cancels, desired)
|
|
|
|
}
|
|
|
|
|
|
|
|
return true, nil
|
|
|
|
}, func(err error) {
|
|
|
|
t.Fatal(err)
|
|
|
|
})
|
|
|
|
}
|