mirror of
https://github.com/hashicorp/vault.git
synced 2025-11-28 14:11:10 +01:00
vault: system using the framework
This commit is contained in:
parent
2d92c2ee10
commit
1be431df51
@ -24,6 +24,12 @@ type Backend struct {
|
|||||||
// backend is in use).
|
// backend is in use).
|
||||||
Paths []*Path
|
Paths []*Path
|
||||||
|
|
||||||
|
// PathsRoot is the list of path patterns that denote the
|
||||||
|
// paths above that require root-level privileges. These can't be
|
||||||
|
// regular expressions, it is either exact match or prefix match.
|
||||||
|
// For prefix match, append '*' as a suffix.
|
||||||
|
PathsRoot []string
|
||||||
|
|
||||||
once sync.Once
|
once sync.Once
|
||||||
pathsRe []*regexp.Regexp
|
pathsRe []*regexp.Regexp
|
||||||
}
|
}
|
||||||
@ -46,12 +52,6 @@ type Path struct {
|
|||||||
// whereas all fields are avaiable in the Write operation.
|
// whereas all fields are avaiable in the Write operation.
|
||||||
Fields map[string]*FieldSchema
|
Fields map[string]*FieldSchema
|
||||||
|
|
||||||
// Root if not blank, denotes that this path requires root
|
|
||||||
// privileges and the path pattern that is the root path. This can't
|
|
||||||
// be a regular expression and must be an exact path. It may have a
|
|
||||||
// trailing '*' to denote that it is a prefix, and not an exact match.
|
|
||||||
Root string
|
|
||||||
|
|
||||||
// Callbacks are the set of callbacks that are called for a given
|
// Callbacks are the set of callbacks that are called for a given
|
||||||
// operation. If a callback for a specific operation is not present,
|
// operation. If a callback for a specific operation is not present,
|
||||||
// then logical.ErrUnsupportedOperation is automatically generated.
|
// then logical.ErrUnsupportedOperation is automatically generated.
|
||||||
@ -123,8 +123,7 @@ func (b *Backend) HandleRequest(req *logical.Request) (*logical.Response, error)
|
|||||||
|
|
||||||
// logical.Backend impl.
|
// logical.Backend impl.
|
||||||
func (b *Backend) RootPaths() []string {
|
func (b *Backend) RootPaths() []string {
|
||||||
// TODO
|
return b.PathsRoot
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Route looks up the path that would be used for a given path string.
|
// Route looks up the path that would be used for a given path string.
|
||||||
|
|||||||
@ -158,7 +158,7 @@ func NewCore(conf *CoreConfig) (*Core, error) {
|
|||||||
}
|
}
|
||||||
backends["generic"] = PassthroughBackendFactory
|
backends["generic"] = PassthroughBackendFactory
|
||||||
backends["system"] = func(map[string]string) (logical.Backend, error) {
|
backends["system"] = func(map[string]string) (logical.Backend, error) {
|
||||||
return &SystemBackend{Core: c}, nil
|
return NewSystemBackend(c), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
c.backends = backends
|
c.backends = backends
|
||||||
|
|||||||
@ -4,8 +4,72 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/vault/logical"
|
"github.com/hashicorp/vault/logical"
|
||||||
|
"github.com/hashicorp/vault/logical/framework"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func NewSystemBackend(core *Core) logical.Backend {
|
||||||
|
b := &SystemBackend{Core: core}
|
||||||
|
|
||||||
|
return &framework.Backend{
|
||||||
|
PathsRoot: []string{
|
||||||
|
"mount/*",
|
||||||
|
"remount",
|
||||||
|
},
|
||||||
|
|
||||||
|
Paths: []*framework.Path{
|
||||||
|
&framework.Path{
|
||||||
|
Pattern: "mounts",
|
||||||
|
|
||||||
|
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||||
|
logical.ReadOperation: b.handleMountTable,
|
||||||
|
},
|
||||||
|
|
||||||
|
HelpSynopsis: strings.TrimSpace(sysHelp["mounts"][0]),
|
||||||
|
HelpDescription: strings.TrimSpace(sysHelp["mounts"][1]),
|
||||||
|
},
|
||||||
|
|
||||||
|
&framework.Path{
|
||||||
|
Pattern: "mount/(?P<path>.+?)",
|
||||||
|
|
||||||
|
Fields: map[string]*framework.FieldSchema{
|
||||||
|
"path": &framework.FieldSchema{
|
||||||
|
Type: framework.TypeString,
|
||||||
|
Description: strings.TrimSpace(sysHelp["mount_path"][0]),
|
||||||
|
},
|
||||||
|
|
||||||
|
"type": &framework.FieldSchema{
|
||||||
|
Type: framework.TypeString,
|
||||||
|
Description: strings.TrimSpace(sysHelp["mount_type"][0]),
|
||||||
|
},
|
||||||
|
"description": &framework.FieldSchema{
|
||||||
|
Type: framework.TypeString,
|
||||||
|
Description: strings.TrimSpace(sysHelp["mount_desc"][0]),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||||
|
logical.WriteOperation: b.handleMount,
|
||||||
|
logical.DeleteOperation: b.handleUnmount,
|
||||||
|
},
|
||||||
|
|
||||||
|
HelpSynopsis: strings.TrimSpace(sysHelp["mount"][0]),
|
||||||
|
HelpDescription: strings.TrimSpace(sysHelp["mount"][1]),
|
||||||
|
},
|
||||||
|
|
||||||
|
&framework.Path{
|
||||||
|
Pattern: "remount",
|
||||||
|
|
||||||
|
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||||
|
logical.WriteOperation: b.handleRemount,
|
||||||
|
},
|
||||||
|
|
||||||
|
HelpSynopsis: strings.TrimSpace(sysHelp["remount"][0]),
|
||||||
|
HelpDescription: strings.TrimSpace(sysHelp["remount"][1]),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SystemBackend implements logical.Backend and is used to interact with
|
// SystemBackend implements logical.Backend and is used to interact with
|
||||||
// the core of the system. This backend is hardcoded to exist at the "sys"
|
// the core of the system. This backend is hardcoded to exist at the "sys"
|
||||||
// prefix. Conceptually it is similar to procfs on Linux.
|
// prefix. Conceptually it is similar to procfs on Linux.
|
||||||
@ -13,35 +77,9 @@ type SystemBackend struct {
|
|||||||
Core *Core
|
Core *Core
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *SystemBackend) HandleRequest(req *logical.Request) (*logical.Response, error) {
|
|
||||||
// Switch on the path to route to the appropriate handler
|
|
||||||
switch {
|
|
||||||
case req.Path == "mounts":
|
|
||||||
return b.handleMountTable(req)
|
|
||||||
case strings.HasPrefix(req.Path, "mount/"):
|
|
||||||
return b.handleMountOperation(req)
|
|
||||||
case req.Path == "remount":
|
|
||||||
return b.handleRemount(req)
|
|
||||||
default:
|
|
||||||
return nil, logical.ErrUnsupportedPath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *SystemBackend) RootPaths() []string {
|
|
||||||
return []string{
|
|
||||||
"mount/*",
|
|
||||||
"remount",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleMountTable handles the "mounts" endpoint to provide the mount table
|
// handleMountTable handles the "mounts" endpoint to provide the mount table
|
||||||
func (b *SystemBackend) handleMountTable(req *logical.Request) (*logical.Response, error) {
|
func (b *SystemBackend) handleMountTable(
|
||||||
switch req.Operation {
|
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
case logical.ReadOperation:
|
|
||||||
default:
|
|
||||||
return nil, logical.ErrUnsupportedOperation
|
|
||||||
}
|
|
||||||
|
|
||||||
b.Core.mountsLock.RLock()
|
b.Core.mountsLock.RLock()
|
||||||
defer b.Core.mountsLock.RUnlock()
|
defer b.Core.mountsLock.RUnlock()
|
||||||
|
|
||||||
@ -60,35 +98,23 @@ func (b *SystemBackend) handleMountTable(req *logical.Request) (*logical.Respons
|
|||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleMountOperation is used to mount or unmount a path
|
|
||||||
func (b *SystemBackend) handleMountOperation(req *logical.Request) (*logical.Response, error) {
|
|
||||||
switch req.Operation {
|
|
||||||
case logical.WriteOperation:
|
|
||||||
return b.handleMount(req)
|
|
||||||
case logical.DeleteOperation:
|
|
||||||
return b.handleUnmount(req)
|
|
||||||
default:
|
|
||||||
return nil, logical.ErrUnsupportedOperation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleMount is used to mount a new path
|
// handleMount is used to mount a new path
|
||||||
func (b *SystemBackend) handleMount(req *logical.Request) (*logical.Response, error) {
|
func (b *SystemBackend) handleMount(
|
||||||
suffix := strings.TrimPrefix(req.Path, "mount/")
|
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
if len(suffix) == 0 {
|
// Get all the options
|
||||||
return logical.ErrorResponse("path cannot be blank"), logical.ErrInvalidRequest
|
path := data.Get("path").(string)
|
||||||
}
|
logicalType := data.Get("type").(string)
|
||||||
|
description := data.Get("description").(string)
|
||||||
|
|
||||||
// Get the type and description (optionally)
|
|
||||||
logicalType := req.GetString("type")
|
|
||||||
if logicalType == "" {
|
if logicalType == "" {
|
||||||
return logical.ErrorResponse("backend type must be specified as a string"), logical.ErrInvalidRequest
|
return logical.ErrorResponse(
|
||||||
|
"backend type must be specified as a string"),
|
||||||
|
logical.ErrInvalidRequest
|
||||||
}
|
}
|
||||||
description := req.GetString("description")
|
|
||||||
|
|
||||||
// Create the mount entry
|
// Create the mount entry
|
||||||
me := &MountEntry{
|
me := &MountEntry{
|
||||||
Path: suffix,
|
Path: path,
|
||||||
Type: logicalType,
|
Type: logicalType,
|
||||||
Description: description,
|
Description: description,
|
||||||
}
|
}
|
||||||
@ -101,7 +127,8 @@ func (b *SystemBackend) handleMount(req *logical.Request) (*logical.Response, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handleUnmount is used to unmount a path
|
// handleUnmount is used to unmount a path
|
||||||
func (b *SystemBackend) handleUnmount(req *logical.Request) (*logical.Response, error) {
|
func (b *SystemBackend) handleUnmount(
|
||||||
|
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
suffix := strings.TrimPrefix(req.Path, "mount/")
|
suffix := strings.TrimPrefix(req.Path, "mount/")
|
||||||
if len(suffix) == 0 {
|
if len(suffix) == 0 {
|
||||||
return logical.ErrorResponse("path cannot be blank"), logical.ErrInvalidRequest
|
return logical.ErrorResponse("path cannot be blank"), logical.ErrInvalidRequest
|
||||||
@ -116,7 +143,8 @@ func (b *SystemBackend) handleUnmount(req *logical.Request) (*logical.Response,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handleRemount is used to remount a path
|
// handleRemount is used to remount a path
|
||||||
func (b *SystemBackend) handleRemount(req *logical.Request) (*logical.Response, error) {
|
func (b *SystemBackend) handleRemount(
|
||||||
|
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
// Only accept write operations
|
// Only accept write operations
|
||||||
switch req.Operation {
|
switch req.Operation {
|
||||||
case logical.WriteOperation:
|
case logical.WriteOperation:
|
||||||
@ -140,3 +168,46 @@ func (b *SystemBackend) handleRemount(req *logical.Request) (*logical.Response,
|
|||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sysHelp is all the help text for the sys backend.
|
||||||
|
var sysHelp = map[string][2]string{
|
||||||
|
"mounts": {
|
||||||
|
"List the currently mounted backends.",
|
||||||
|
`
|
||||||
|
List the currently mounted backends: the mount path, the type of the backend,
|
||||||
|
and a user friendly description of the purpose for the mount.
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
|
||||||
|
"mount": {
|
||||||
|
`Mount a new backend at a new path.`,
|
||||||
|
`
|
||||||
|
Mount a backend at a new path. A backend can be mounted multiple times at
|
||||||
|
multiple paths in order to configure multiple separately configured backends.
|
||||||
|
Example: you might have an AWS backend for the east coast, and one for the
|
||||||
|
west coast.
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
|
||||||
|
"mount_path": {
|
||||||
|
`The path to mount to. Example: "aws/east"`,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
|
||||||
|
"mount_type": {
|
||||||
|
`The type of the backend. Example: "passthrough"`,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
|
||||||
|
"mount_desc": {
|
||||||
|
`User-friendly description for this mount.`,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
|
||||||
|
"remount": {
|
||||||
|
"Move the mount point of an already-mounted backend.",
|
||||||
|
`
|
||||||
|
Change the mount point of an already-mounted backend.
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|||||||
@ -7,10 +7,6 @@ import (
|
|||||||
"github.com/hashicorp/vault/logical"
|
"github.com/hashicorp/vault/logical"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSystemBackend_impl(t *testing.T) {
|
|
||||||
var _ logical.Backend = new(SystemBackend)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSystemBackend_RootPaths(t *testing.T) {
|
func TestSystemBackend_RootPaths(t *testing.T) {
|
||||||
expected := []string{
|
expected := []string{
|
||||||
"mount/*",
|
"mount/*",
|
||||||
@ -147,7 +143,7 @@ func TestSystemBackend_remount_system(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSystemBackend(t *testing.T) *SystemBackend {
|
func testSystemBackend(t *testing.T) logical.Backend {
|
||||||
c, _ := TestCoreUnsealed(t)
|
c, _ := TestCoreUnsealed(t)
|
||||||
return &SystemBackend{Core: c}
|
return NewSystemBackend(c)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user