Skip to content

Commit 16ec448

Browse files
committed
Improve Vault error handling
1 parent b4bb89d commit 16ec448

File tree

4 files changed

+43
-13
lines changed

4 files changed

+43
-13
lines changed

client/client.go

+20-3
Original file line numberDiff line numberDiff line change
@@ -1939,10 +1939,27 @@ func (c *Client) deriveToken(alloc *structs.Allocation, taskNames []string, vcli
19391939
// Unwrap the vault token
19401940
unwrapResp, err := vclient.Logical().Unwrap(wrappedToken)
19411941
if err != nil {
1942-
return nil, fmt.Errorf("failed to unwrap the token for task %q: %v", taskName, err)
1942+
if structs.VaultUnrecoverableError.MatchString(err.Error()) {
1943+
return nil, err
1944+
}
1945+
1946+
// The error is recoverable
1947+
return nil, structs.NewRecoverableError(
1948+
fmt.Errorf("failed to unwrap the token for task %q: %v", taskName, err), true)
1949+
}
1950+
1951+
// Validate the response
1952+
var validationErr error
1953+
if unwrapResp == nil {
1954+
validationErr = fmt.Errorf("Vault returned nil secret when unwrapping")
1955+
} else if unwrapResp.Auth == nil {
1956+
validationErr = fmt.Errorf("Vault returned unwrap secret with nil Auth. Secret warnings: %v", unwrapResp.Warnings)
1957+
} else if unwrapResp.Auth.ClientToken == "" {
1958+
validationErr = fmt.Errorf("Vault returned unwrap secret with empty Auth.ClientToken. Secret warnings: %v", unwrapResp.Warnings)
19431959
}
1944-
if unwrapResp == nil || unwrapResp.Auth == nil || unwrapResp.Auth.ClientToken == "" {
1945-
return nil, fmt.Errorf("failed to unwrap the token for task %q", taskName)
1960+
if validationErr != nil {
1961+
c.logger.Printf("[WARN] client.vault: failed to unwrap token: %v", err)
1962+
return nil, structs.NewRecoverableError(validationErr, true)
19461963
}
19471964

19481965
// Append the unwrapped token to the return value

nomad/node_endpoint.go

-4
Original file line numberDiff line numberDiff line change
@@ -1398,10 +1398,6 @@ func (n *Node) DeriveVaultToken(args *structs.DeriveVaultTokenRequest,
13981398
tokens := make(map[string]string, len(results))
13991399
for task, secret := range results {
14001400
w := secret.WrapInfo
1401-
if w == nil {
1402-
return fmt.Errorf("Vault returned Secret without WrapInfo")
1403-
}
1404-
14051401
tokens[task] = w.Token
14061402
accessor := &structs.VaultAccessor{
14071403
Accessor: w.WrappedAccessor,

nomad/structs/structs.go

+6
Original file line numberDiff line numberDiff line change
@@ -5136,6 +5136,12 @@ func (d *EphemeralDisk) Copy() *EphemeralDisk {
51365136
return ld
51375137
}
51385138

5139+
var (
5140+
// VaultUnrecoverableError matches unrecoverable errors returned by a Vault
5141+
// server
5142+
VaultUnrecoverableError = regexp.MustCompile(`Code:\s+40(0|3|4)`)
5143+
)
5144+
51395145
const (
51405146
// VaultChangeModeNoop takes no action when a new token is retrieved.
51415147
VaultChangeModeNoop = "noop"

nomad/vault.go

+17-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"fmt"
77
"log"
88
"math/rand"
9-
"regexp"
109
"sync"
1110
"sync/atomic"
1211
"time"
@@ -70,9 +69,6 @@ const (
7069
)
7170

7271
var (
73-
// vaultUnrecoverableError matches unrecoverable errors
74-
vaultUnrecoverableError = regexp.MustCompile(`Code:\s+40(0|3|4)`)
75-
7672
// vaultCapabilitiesCapability is the expected capability of Nomad's Vault
7773
// token on the the path. The token must have at least one of the
7874
// capabilities.
@@ -695,7 +691,7 @@ func (v *vaultClient) validateCapabilities(role string, root bool) error {
695691
_, _, err := v.hasCapability(vaultCapabilitiesLookupPath, vaultCapabilitiesCapability)
696692
if err != nil {
697693
// Check if there is a permission denied
698-
if vaultUnrecoverableError.MatchString(err.Error()) {
694+
if structs.VaultUnrecoverableError.MatchString(err.Error()) {
699695
// Since we can't read permissions, we just log a warning that we
700696
// can't tell if the Vault token will work
701697
msg := fmt.Sprintf("Can not lookup token capabilities. "+
@@ -894,14 +890,29 @@ func (v *vaultClient) CreateToken(ctx context.Context, a *structs.Allocation, ta
894890

895891
// Determine whether it is unrecoverable
896892
if err != nil {
897-
if vaultUnrecoverableError.MatchString(err.Error()) {
893+
if structs.VaultUnrecoverableError.MatchString(err.Error()) {
898894
return secret, err
899895
}
900896

901897
// The error is recoverable
902898
return nil, structs.NewRecoverableError(err, true)
903899
}
904900

901+
// Validate the response
902+
var validationErr error
903+
if secret == nil {
904+
validationErr = fmt.Errorf("Vault returned nil Secret")
905+
} else if secret.WrapInfo == nil {
906+
validationErr = fmt.Errorf("Vault returned Secret with nil WrapInfo. Secret warnings: %v", secret.Warnings)
907+
} else if secret.WrapInfo.WrappedAccessor == "" {
908+
validationErr = fmt.Errorf("Vault returned WrapInfo without WrappedAccessor. Secret warnings: %v", secret.Warnings)
909+
}
910+
if validationErr != nil {
911+
v.logger.Printf("[WARN] vault: failed to CreateToken: %v", err)
912+
return nil, structs.NewRecoverableError(validationErr, true)
913+
}
914+
915+
// Got a valid response
905916
return secret, nil
906917
}
907918

0 commit comments

Comments
 (0)