Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport of When tainting a route during setup, pre-calculate the namespace specific path into release/1.9.x #15181

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions helper/namespace/namespace.go
Expand Up @@ -3,6 +3,7 @@ package namespace
import (
"context"
"errors"
"fmt"
"strings"
)

Expand All @@ -13,6 +14,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"
)
Expand Down
9 changes: 6 additions & 3 deletions vault/auth.go
Expand Up @@ -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"
Expand Down Expand Up @@ -723,16 +723,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)
}

Expand Down
30 changes: 24 additions & 6 deletions vault/router.go
Expand Up @@ -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"
Expand Down Expand Up @@ -522,15 +522,27 @@ func (r *Router) routeCommon(ctx context.Context, req *logical.Request, existenc
r.l.RLock()
adjustedPath := req.Path
mount, raw, ok := r.root.LongestPrefix(ns.Path + adjustedPath)
if r.logger.IsTrace() {
r.logger.Trace("trying to route to mount using adjusted path", "namespace", ns, "adjustedPath", adjustedPath)
if !ok {
r.logger.Trace("prefix search returned", "mount", mount, "raw", raw)
}
}
if !ok && !strings.HasSuffix(adjustedPath, "/") {
// Re-check for a backend by appending a slash. This lets "foo" mean
// "foo/" at the root level which is almost always what we want.
adjustedPath += "/"
mount, raw, ok = r.root.LongestPrefix(ns.Path + adjustedPath)
if r.logger.IsTrace() {
r.logger.Trace("after appending / to adjustedPath, trying again to route to mount using adjusted path", "namespace", ns, "adjustedPath", adjustedPath)
if !ok {
r.logger.Trace("after appending / to adjustedPath, prefix search returned", "mount", mount, "raw", raw)
}
}
}
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 '%s', route entry not found", req.Path)), false, false, logical.ErrUnsupportedPath
}
req.Path = adjustedPath
defer metrics.MeasureSince([]string{
Expand All @@ -551,7 +563,10 @@ 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
if r.logger.IsTrace() {
r.logger.Trace("route entry found, but backend is nil")
}
return logical.ErrorResponse(fmt.Sprintf("no handler for route '%s', nil backend", req.Path)), false, false, logical.ErrUnsupportedPath
}

// If the path is tainted, we reject any operation except for
Expand All @@ -560,7 +575,10 @@ 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
if r.logger.IsTrace() {
r.logger.Trace("route entry is tainted, rejecting operations to it that aren't revoke or rollback")
}
return logical.ErrorResponse(fmt.Sprintf("no handler for route '%s', entry tainted", req.Path)), false, false, logical.ErrUnsupportedPath
}
}

Expand Down