open-vault/vault/system.go
Mitchell Hashimoto b2af154fb4 vault: make Mount related core functions public
/cc @armon - So I know the conversation we had related to this about
auth, but I think we still need to export these and do auth only at the
external API layer. If you're writing to the internal API, then all bets
are off.

The reason is simply that if you have access to the code, you can
already work around it anyways (you can disable auth or w/e), so a
compromised Vault source/binary is already a failure, and that is the
only thing that our previous unexported methods were protecting against.

If you write an external tool to access a Vault, it still needs to be
unsealed so _that_ is the primary security mechanism from an API
perspective. Once it is unsealed then the core API has full access to
the Vault, and identity/auth is only done at the external API layer, not
at the internal API layer.

The benefits of this approach is that it lets us still treat the "sys"
mount specially but at least have sys adopt helper/backend and use that
machinery and it can still be the only backend which actually has a
reference to *vault.Core to do core things (a key difference). So, an
AWS backend still will never be able to muck with things it can't, but
we're explicitly giving Sys (via struct initialization in Go itself)
a reference to *vault.Core.
2015-03-14 17:26:59 -07:00

140 lines
3.7 KiB
Go

package vault
import "strings"
// SystemBackend implements the LogicalBackend interface but is used
// to interact with the core of the system. It acts like a "procfs"
// to provide a uniform interface to vault.
type SystemBackend struct {
core *Core
}
func (s *SystemBackend) HandleRequest(req *Request) (*Response, error) {
// Switch on the path to route to the appropriate handler
switch {
case req.Path == "mounts":
return s.handleMountTable(req)
case strings.HasPrefix(req.Path, "mount/"):
return s.handleMountOperation(req)
case req.Path == "remount":
return s.handleRemount(req)
default:
return nil, ErrUnsupportedPath
}
}
func (s *SystemBackend) RootPaths() []string {
return []string{
"mount/*",
"remount",
}
}
// handleMountTable handles the "mounts" endpoint to provide the mount table
func (s *SystemBackend) handleMountTable(req *Request) (*Response, error) {
switch req.Operation {
case ReadOperation:
case HelpOperation:
return HelpResponse("logical backend mount table", []string{"sys/mount/"}), nil
default:
return nil, ErrUnsupportedOperation
}
s.core.mountsLock.RLock()
defer s.core.mountsLock.RUnlock()
resp := &Response{
IsSecret: false,
Data: make(map[string]interface{}),
}
for _, entry := range s.core.mounts.Entries {
info := map[string]string{
"type": entry.Type,
"description": entry.Description,
}
resp.Data[entry.Path] = info
}
return resp, nil
}
// handleMountOperation is used to mount or unmount a path
func (s *SystemBackend) handleMountOperation(req *Request) (*Response, error) {
switch req.Operation {
case WriteOperation:
return s.handleMount(req)
case DeleteOperation:
return s.handleUnmount(req)
case HelpOperation:
return HelpResponse("used to mount or unmount a path", []string{"sys/mounts"}), nil
default:
return nil, ErrUnsupportedOperation
}
}
// handleMount is used to mount a new path
func (s *SystemBackend) handleMount(req *Request) (*Response, error) {
suffix := strings.TrimPrefix(req.Path, "mount/")
if len(suffix) == 0 {
return ErrorResponse("path cannot be blank"), ErrInvalidRequest
}
// Get the type and description (optionally)
logicalType := req.GetString("type")
if logicalType == "" {
return ErrorResponse("backend type must be specified as a string"), ErrInvalidRequest
}
description := req.GetString("description")
// Create the mount entry
me := &MountEntry{
Path: suffix,
Type: logicalType,
Description: description,
}
// Attempt mount
if err := s.core.Mount(me); err != nil {
return ErrorResponse(err.Error()), ErrInvalidRequest
}
return nil, nil
}
// handleUnmount is used to unmount a path
func (s *SystemBackend) handleUnmount(req *Request) (*Response, error) {
suffix := strings.TrimPrefix(req.Path, "mount/")
if len(suffix) == 0 {
return ErrorResponse("path cannot be blank"), ErrInvalidRequest
}
// Attempt unmount
if err := s.core.Unmount(suffix); err != nil {
return ErrorResponse(err.Error()), ErrInvalidRequest
}
return nil, nil
}
// handleRemount is used to remount a path
func (s *SystemBackend) handleRemount(req *Request) (*Response, error) {
// Only accept write operations
switch req.Operation {
case WriteOperation:
case HelpOperation:
return HelpResponse("remount a backend path", []string{"sys/mount/", "sys/mounts"}), nil
default:
return nil, ErrUnsupportedOperation
}
// Get the paths
fromPath := req.GetString("from")
toPath := req.GetString("to")
if fromPath == "" || toPath == "" {
return ErrorResponse("both 'from' and 'to' path must be specified as a string"), ErrInvalidRequest
}
// Attempt remount
if err := s.core.Remount(fromPath, toPath); err != nil {
return ErrorResponse(err.Error()), ErrInvalidRequest
}
return nil, nil
}