From f3853f11daa51336a2d46d883b1aff6feeddc7ec Mon Sep 17 00:00:00 2001 From: Mahmood Ali Date: Thu, 29 Nov 2018 09:09:55 -0500 Subject: [PATCH] vault: protect against empty Vault secret response Also, fix a case where a successful second attempt of loading token can cause a panic. --- nomad/vault.go | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/nomad/vault.go b/nomad/vault.go index cedfd056402e..f866a8d20b74 100644 --- a/nomad/vault.go +++ b/nomad/vault.go @@ -630,24 +630,15 @@ func (v *vaultClient) getWrappingFn() func(operation, path string) string { // it in the client. If the token is not valid for Nomads purposes an error is // returned. func (v *vaultClient) parseSelfToken() error { - // Get the initial lease duration - auth := v.client.Auth().Token() - var self *vapi.Secret - // Try looking up the token using the self endpoint - secret, err := auth.LookupSelf() + secret, err := v.lookupSelf() if err != nil { - // Try looking up our token directly - self, err = auth.Lookup(v.client.Token()) - if err != nil { - return fmt.Errorf("failed to lookup Vault periodic token: %v", err) - } + return err } - self = secret // Read and parse the fields var data tokenData - if err := mapstructure.WeakDecode(self.Data, &data); err != nil { + if err := mapstructure.WeakDecode(secret.Data, &data); err != nil { return fmt.Errorf("failed to parse Vault token's data block: %v", err) } root := false @@ -724,6 +715,29 @@ func (v *vaultClient) parseSelfToken() error { return mErr.ErrorOrNil() } +// lookupSelf is a helper function that looks up latest self lease info. +func (v *vaultClient) lookupSelf() (*vapi.Secret, error) { + // Get the initial lease duration + auth := v.client.Auth().Token() + + secret, err := auth.LookupSelf() + if err == nil && secret != nil && secret.Data != nil { + return secret, nil + } + + // Try looking up our token directly, even when we get an empty response, + // in case of an unexpected event - a true failure would occur in this lookup again + secret, err = auth.Lookup(v.client.Token()) + switch { + case err != nil: + return nil, fmt.Errorf("failed to lookup Vault periodic token: %v", err) + case secret == nil || secret.Data == nil: + return nil, fmt.Errorf("failed to lookup Vault periodic token: got empty response") + default: + return secret, nil + } +} + // getRole returns the role name to be used when creating tokens func (v *vaultClient) getRole() string { if v.config.Role != "" {