diff --git a/changelog/15067.txt b/changelog/15067.txt new file mode 100644 index 0000000000000..4adee8fb6a49a --- /dev/null +++ b/changelog/15067.txt @@ -0,0 +1,3 @@ +```release-note:bug +core: pre-calculate namespace specific paths when tainting a route during postUnseal +``` diff --git a/helper/namespace/namespace.go b/helper/namespace/namespace.go index 045d2abe454d5..90ddadefd62df 100644 --- a/helper/namespace/namespace.go +++ b/helper/namespace/namespace.go @@ -3,6 +3,7 @@ package namespace import ( "context" "errors" + "fmt" "strings" "github.com/hashicorp/vault/sdk/helper/consts" @@ -15,6 +16,10 @@ type Namespace struct { Path string `json:"path"` } +func (n *Namespace) String() string { + return fmt.Sprintf("ID: %s. Path: %s", n.ID, n.Path) +} + const ( RootNamespaceID = "root" ) diff --git a/vault/auth.go b/vault/auth.go index 282260f27b31b..0aea3f50e3ab5 100644 --- a/vault/auth.go +++ b/vault/auth.go @@ -7,7 +7,7 @@ import ( "strings" "github.com/hashicorp/go-secure-stdlib/strutil" - uuid "github.com/hashicorp/go-uuid" + "github.com/hashicorp/go-uuid" "github.com/hashicorp/vault/builtin/plugin" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/sdk/helper/consts" @@ -825,16 +825,19 @@ func (c *Core) setupCredentials(ctx context.Context) error { path := credentialRoutePrefix + entry.Path err = c.router.Mount(backend, path, entry, view) if err != nil { - c.logger.Error("failed to mount auth entry", "path", entry.Path, "error", err) + c.logger.Error("failed to mount auth entry", "path", entry.Path, "namespace", entry.Namespace(), "error", err) return errLoadAuthFailed } if c.logger.IsInfo() { - c.logger.Info("successfully enabled credential backend", "type", entry.Type, "path", entry.Path) + c.logger.Info("successfully enabled credential backend", "type", entry.Type, "path", entry.Path, "namespace", entry.Namespace()) } // Ensure the path is tainted if set in the mount table if entry.Tainted { + // Calculate any namespace prefixes here, because when Taint() is called, there won't be + // a namespace to pull from the context. This is similar to what we do above in c.router.Mount(). + path = entry.Namespace().Path + path c.router.Taint(ctx, path) } diff --git a/vault/rollback_test.go b/vault/rollback_test.go index 4308d70e1c2e5..681101217a30e 100644 --- a/vault/rollback_test.go +++ b/vault/rollback_test.go @@ -7,8 +7,7 @@ import ( "time" log "github.com/hashicorp/go-hclog" - uuid "github.com/hashicorp/go-uuid" - + "github.com/hashicorp/go-uuid" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/sdk/helper/logging" ) diff --git a/vault/router.go b/vault/router.go index a75167059bf60..1c11234eb1de0 100644 --- a/vault/router.go +++ b/vault/router.go @@ -9,9 +9,9 @@ import ( "sync/atomic" "time" - metrics "github.com/armon/go-metrics" - radix "github.com/armon/go-radix" - hclog "github.com/hashicorp/go-hclog" + "github.com/armon/go-metrics" + "github.com/armon/go-radix" + "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-secure-stdlib/strutil" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/sdk/helper/consts" @@ -47,6 +47,8 @@ func NewRouter() *Router { storagePrefix: radix.New(), mountUUIDCache: radix.New(), mountAccessorCache: radix.New(), + // this will get replaced in production with a real logger but it's useful to have a default in place for tests + logger: hclog.NewNullLogger(), } return r } @@ -530,7 +532,7 @@ func (r *Router) routeCommon(ctx context.Context, req *logical.Request, existenc } r.l.RUnlock() if !ok { - return logical.ErrorResponse(fmt.Sprintf("no handler for route '%s'", req.Path)), false, false, logical.ErrUnsupportedPath + return logical.ErrorResponse(fmt.Sprintf("no handler for route %q. route entry not found.", req.Path)), false, false, logical.ErrUnsupportedPath } req.Path = adjustedPath defer metrics.MeasureSince([]string{ @@ -551,7 +553,7 @@ func (r *Router) routeCommon(ctx context.Context, req *logical.Request, existenc // Filtered mounts will have a nil backend if re.backend == nil { - return logical.ErrorResponse(fmt.Sprintf("no handler for route '%s'", req.Path)), false, false, logical.ErrUnsupportedPath + return logical.ErrorResponse(fmt.Sprintf("no handler for route %q. route entry found, but backend is nil.", req.Path)), false, false, logical.ErrUnsupportedPath } // If the path is tainted, we reject any operation except for @@ -560,7 +562,7 @@ func (r *Router) routeCommon(ctx context.Context, req *logical.Request, existenc switch req.Operation { case logical.RevokeOperation, logical.RollbackOperation: default: - return logical.ErrorResponse(fmt.Sprintf("no handler for route '%s'", req.Path)), false, false, logical.ErrUnsupportedPath + return logical.ErrorResponse(fmt.Sprintf("no handler for route %q. route entry is tainted.", req.Path)), false, false, logical.ErrUnsupportedPath } } diff --git a/vault/router_test.go b/vault/router_test.go index b7ade5ca24ae0..2a2340a51c14e 100644 --- a/vault/router_test.go +++ b/vault/router_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - uuid "github.com/hashicorp/go-uuid" + "github.com/hashicorp/go-uuid" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/sdk/logical" )