mirror of
https://github.com/kemko/nomad.git
synced 2026-01-03 17:05:43 +03:00
The legacy workflow for Vault whereby servers were configured using a token to provide authentication to the Vault API has now been removed. This change also removes the workflow where servers were responsible for deriving Vault tokens for Nomad clients. The deprecated Vault config options used byi the Nomad agent have all been removed except for "token" which is still in use by the Vault Transit keyring implementation. Job specification authors can no longer use the "vault.policies" parameter and should instead use "vault.role" when not using the default workload identity. --------- Co-authored-by: Tim Gross <tgross@hashicorp.com> Co-authored-by: Aimee Ukasick <aimee.ukasick@hashicorp.com>
169 lines
4.2 KiB
Go
169 lines
4.2 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package vaultclient
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/hashicorp/nomad/helper/uuid"
|
|
)
|
|
|
|
// MockVaultClient is used for testing the vaultclient integration and is safe
|
|
// for concurrent access.
|
|
type MockVaultClient struct {
|
|
|
|
// jwtTokens stores the tokens derived using the JWT flow.
|
|
jwtTokens map[string]string
|
|
|
|
// stoppedTokens tracks the tokens that have stopped renewing
|
|
stoppedTokens []string
|
|
|
|
// renewTokens are the tokens that have been renewed and their error
|
|
// channels
|
|
renewTokens map[string]chan error
|
|
|
|
// renewTokenErrors is used to return an error when the RenewToken is called
|
|
// with the given token
|
|
renewTokenErrors map[string]error
|
|
|
|
// deriveTokenErrors maps an allocation ID and tasks to an error when the
|
|
// token is derived
|
|
deriveTokenErrors map[string]map[string]error
|
|
|
|
// deriveTokenWithJWTFn allows the caller to control the DeriveTokenWithJWT
|
|
// function.
|
|
deriveTokenWithJWTFn func(context.Context, JWTLoginRequest) (string, bool, error)
|
|
|
|
// renewable determines if the tokens returned should be marked as renewable
|
|
renewable bool
|
|
|
|
mu sync.Mutex
|
|
}
|
|
|
|
// NewMockVaultClient returns a MockVaultClient for testing
|
|
func NewMockVaultClient(_ string) (VaultClient, error) {
|
|
return &MockVaultClient{renewable: true}, nil
|
|
}
|
|
|
|
func (vc *MockVaultClient) DeriveTokenWithJWT(ctx context.Context, req JWTLoginRequest) (string, bool, error) {
|
|
vc.mu.Lock()
|
|
defer vc.mu.Unlock()
|
|
|
|
if vc.deriveTokenWithJWTFn != nil {
|
|
return vc.deriveTokenWithJWTFn(ctx, req)
|
|
}
|
|
|
|
if vc.jwtTokens == nil {
|
|
vc.jwtTokens = make(map[string]string)
|
|
}
|
|
|
|
token := uuid.Generate()
|
|
if req.Role != "" {
|
|
token = fmt.Sprintf("%s-%s", token, req.Role)
|
|
}
|
|
vc.jwtTokens[req.JWT] = token
|
|
return token, vc.renewable, nil
|
|
}
|
|
|
|
func (vc *MockVaultClient) SetDeriveTokenError(allocID string, tasks []string, err error) {
|
|
vc.mu.Lock()
|
|
defer vc.mu.Unlock()
|
|
|
|
if vc.deriveTokenErrors == nil {
|
|
vc.deriveTokenErrors = make(map[string]map[string]error, 10)
|
|
}
|
|
|
|
if _, ok := vc.deriveTokenErrors[allocID]; !ok {
|
|
vc.deriveTokenErrors[allocID] = make(map[string]error, 10)
|
|
}
|
|
|
|
for _, task := range tasks {
|
|
vc.deriveTokenErrors[allocID][task] = err
|
|
}
|
|
}
|
|
|
|
func (vc *MockVaultClient) RenewToken(token string, interval int) (<-chan error, error) {
|
|
vc.mu.Lock()
|
|
defer vc.mu.Unlock()
|
|
|
|
if err, ok := vc.renewTokenErrors[token]; ok {
|
|
return nil, err
|
|
}
|
|
|
|
renewCh := make(chan error)
|
|
if vc.renewTokens == nil {
|
|
vc.renewTokens = make(map[string]chan error, 10)
|
|
}
|
|
vc.renewTokens[token] = renewCh
|
|
return renewCh, nil
|
|
}
|
|
|
|
func (vc *MockVaultClient) SetRenewTokenError(token string, err error) {
|
|
vc.mu.Lock()
|
|
defer vc.mu.Unlock()
|
|
|
|
if vc.renewTokenErrors == nil {
|
|
vc.renewTokenErrors = make(map[string]error, 10)
|
|
}
|
|
|
|
vc.renewTokenErrors[token] = err
|
|
}
|
|
|
|
func (vc *MockVaultClient) StopRenewToken(token string) error {
|
|
vc.mu.Lock()
|
|
defer vc.mu.Unlock()
|
|
|
|
vc.stoppedTokens = append(vc.stoppedTokens, token)
|
|
return nil
|
|
}
|
|
|
|
func (vc *MockVaultClient) Start() {}
|
|
|
|
func (vc *MockVaultClient) Stop() {}
|
|
|
|
func (vc *MockVaultClient) SetRenewable(renewable bool) {
|
|
vc.mu.Lock()
|
|
defer vc.mu.Unlock()
|
|
vc.renewable = renewable
|
|
}
|
|
|
|
// JWTTokens returns the tokens generated suing the JWT flow.
|
|
func (vc *MockVaultClient) JWTTokens() map[string]string {
|
|
vc.mu.Lock()
|
|
defer vc.mu.Unlock()
|
|
return vc.jwtTokens
|
|
}
|
|
|
|
// StoppedTokens tracks the tokens that have stopped renewing
|
|
func (vc *MockVaultClient) StoppedTokens() []string {
|
|
vc.mu.Lock()
|
|
defer vc.mu.Unlock()
|
|
return vc.stoppedTokens
|
|
}
|
|
|
|
// RenewTokens are the tokens that have been renewed and their error
|
|
// channels
|
|
func (vc *MockVaultClient) RenewTokens() map[string]chan error {
|
|
vc.mu.Lock()
|
|
defer vc.mu.Unlock()
|
|
return vc.renewTokens
|
|
}
|
|
|
|
// RenewTokenErrCh returns the error channel for the given token renewal
|
|
// process.
|
|
func (vc *MockVaultClient) RenewTokenErrCh(token string) chan error {
|
|
vc.mu.Lock()
|
|
defer vc.mu.Unlock()
|
|
return vc.renewTokens[token]
|
|
}
|
|
|
|
// SetDeriveTokenWithJWTFn sets the function used to derive tokens using JWT.
|
|
func (vc *MockVaultClient) SetDeriveTokenWithJWTFn(f func(context.Context, JWTLoginRequest) (string, bool, error)) {
|
|
vc.mu.Lock()
|
|
defer vc.mu.Unlock()
|
|
vc.deriveTokenWithJWTFn = f
|
|
}
|