vault: Support tainting router paths

This commit is contained in:
Armon Dadgar 2015-04-02 11:12:13 -07:00
parent c718408055
commit 3e427910fb
2 changed files with 63 additions and 0 deletions

View File

@ -25,6 +25,7 @@ func NewRouter() *Router {
// mountEntry is used to represent a mount point
type mountEntry struct {
tainted bool
backend logical.Backend
view *BarrierView
rootPaths *radix.Tree
@ -49,6 +50,7 @@ func (r *Router) Mount(backend logical.Backend, prefix string, view *BarrierView
// Create a mount entry
me := &mountEntry{
tainted: false,
backend: backend,
view: view,
rootPaths: pathsToRadix(paths.Root),
@ -83,6 +85,18 @@ func (r *Router) Remount(src, dst string) error {
return nil
}
// Taint is used to mark a path as tainted. This means only RollbackOperation
// RenewOperation requests are allowed to proceed
func (r *Router) Taint(path string) error {
r.l.Lock()
defer r.l.Unlock()
_, raw, ok := r.root.LongestPrefix(path)
if ok {
raw.(*mountEntry).tainted = true
}
return nil
}
// MatchingMount returns the mount prefix that would be used for a path
func (r *Router) MatchingMount(path string) string {
r.l.RLock()
@ -116,6 +130,16 @@ func (r *Router) Route(req *logical.Request) (*logical.Response, error) {
}
me := raw.(*mountEntry)
// If the path is tainted, we reject any operation except for
// Rollback and Revoke
if me.tainted {
switch req.Operation {
case logical.RevokeOperation, logical.RollbackOperation:
default:
return nil, fmt.Errorf("no handler for route '%s'", req.Path)
}
}
// Determine if this path is an unauthenticated path before we modify it
loginPath := r.LoginPath(req.Path)

View File

@ -261,6 +261,45 @@ func TestRouter_LoginPath(t *testing.T) {
}
}
func TestRouter_Taint(t *testing.T) {
r := NewRouter()
_, barrier, _ := mockBarrier(t)
view := NewBarrierView(barrier, "logical/")
n := &NoopBackend{}
err := r.Mount(n, "prod/aws/", view)
if err != nil {
t.Fatalf("err: %v", err)
}
err = r.Taint("prod/aws/")
if err != nil {
t.Fatalf("err: %v", err)
}
req := &logical.Request{
Operation: logical.ReadOperation,
Path: "prod/aws/foo",
}
_, err = r.Route(req)
if err.Error() != "no handler for route 'prod/aws/foo'" {
t.Fatalf("err: %v", err)
}
// Rollback and Revoke should work
req.Operation = logical.RollbackOperation
_, err = r.Route(req)
if err != nil {
t.Fatalf("err: %v", err)
}
req.Operation = logical.RevokeOperation
_, err = r.Route(req)
if err != nil {
t.Fatalf("err: %v", err)
}
}
func TestPathsToRadix(t *testing.T) {
// Provide real paths
paths := []string{