2015-03-11 22:19:41 +00:00
|
|
|
package vault
|
|
|
|
|
|
|
|
import (
|
2015-04-04 00:46:57 +00:00
|
|
|
"crypto/sha1"
|
2015-03-11 22:19:41 +00:00
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
2015-03-12 01:19:40 +00:00
|
|
|
"fmt"
|
|
|
|
"strings"
|
2015-03-17 22:28:01 +00:00
|
|
|
"sync"
|
2015-08-28 21:25:09 +00:00
|
|
|
"time"
|
2015-03-15 21:53:41 +00:00
|
|
|
|
2015-06-30 19:38:32 +00:00
|
|
|
"github.com/hashicorp/vault/helper/uuid"
|
2015-03-15 21:53:41 +00:00
|
|
|
"github.com/hashicorp/vault/logical"
|
2015-03-11 22:19:41 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// coreMountConfigPath is used to store the mount configuration.
|
|
|
|
// Mounts are protected within the Vault itself, which means they
|
|
|
|
// can only be viewed or modified after an unseal.
|
|
|
|
coreMountConfigPath = "core/mounts"
|
2015-03-11 22:50:27 +00:00
|
|
|
|
|
|
|
// backendBarrierPrefix is the prefix to the UUID used in the
|
|
|
|
// barrier view for the backends.
|
|
|
|
backendBarrierPrefix = "logical/"
|
2015-03-12 19:41:12 +00:00
|
|
|
|
2015-08-10 17:27:25 +00:00
|
|
|
// systemBarrierPrefix is the prefix used for the
|
2015-03-12 19:41:12 +00:00
|
|
|
// system logical backend.
|
|
|
|
systemBarrierPrefix = "sys/"
|
2015-03-11 22:50:27 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// loadMountsFailed if loadMounts encounters an error
|
2015-08-28 21:25:09 +00:00
|
|
|
errLoadMountsFailed = errors.New("failed to setup mount table")
|
2015-03-12 19:09:30 +00:00
|
|
|
|
|
|
|
// protectedMounts cannot be remounted
|
|
|
|
protectedMounts = []string{
|
2015-03-27 21:00:57 +00:00
|
|
|
"audit/",
|
2015-03-18 22:16:52 +00:00
|
|
|
"auth/",
|
2015-03-12 19:09:30 +00:00
|
|
|
"sys/",
|
|
|
|
}
|
2015-03-11 22:19:41 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// MountTable is used to represent the internal mount table
|
|
|
|
type MountTable struct {
|
2015-03-17 22:28:01 +00:00
|
|
|
// This lock should be held whenever modifying the Entries field.
|
|
|
|
sync.RWMutex
|
|
|
|
|
2015-03-11 22:19:41 +00:00
|
|
|
Entries []*MountEntry `json:"entries"`
|
|
|
|
}
|
|
|
|
|
2015-03-12 01:19:40 +00:00
|
|
|
// Returns a deep copy of the mount table
|
|
|
|
func (t *MountTable) Clone() *MountTable {
|
|
|
|
mt := &MountTable{
|
|
|
|
Entries: make([]*MountEntry, len(t.Entries)),
|
|
|
|
}
|
|
|
|
for i, e := range t.Entries {
|
|
|
|
mt.Entries[i] = e.Clone()
|
|
|
|
}
|
|
|
|
return mt
|
|
|
|
}
|
|
|
|
|
2015-04-04 00:46:57 +00:00
|
|
|
// Hash is used to generate a hash value for the mount table
|
|
|
|
func (t *MountTable) Hash() ([]byte, error) {
|
|
|
|
buf, err := json.Marshal(t)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
hash := sha1.Sum(buf)
|
|
|
|
return hash[:], nil
|
|
|
|
}
|
|
|
|
|
2015-04-03 22:59:30 +00:00
|
|
|
// Find is used to lookup an entry
|
|
|
|
func (t *MountTable) Find(path string) *MountEntry {
|
|
|
|
n := len(t.Entries)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
if t.Entries[i].Path == path {
|
|
|
|
return t.Entries[i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetTaint is used to set the taint on given entry
|
2015-04-03 23:07:45 +00:00
|
|
|
func (t *MountTable) SetTaint(path string, value bool) bool {
|
2015-04-03 22:59:30 +00:00
|
|
|
n := len(t.Entries)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
if t.Entries[i].Path == path {
|
|
|
|
t.Entries[i].Tainted = value
|
2015-04-03 23:07:45 +00:00
|
|
|
return true
|
2015-04-03 22:59:30 +00:00
|
|
|
}
|
|
|
|
}
|
2015-04-03 23:07:45 +00:00
|
|
|
return false
|
2015-04-03 22:59:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Remove is used to remove a given path entry
|
2015-04-03 23:00:46 +00:00
|
|
|
func (t *MountTable) Remove(path string) bool {
|
2015-04-03 22:59:30 +00:00
|
|
|
n := len(t.Entries)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
if t.Entries[i].Path == path {
|
|
|
|
t.Entries[i], t.Entries[n-1] = t.Entries[n-1], nil
|
|
|
|
t.Entries = t.Entries[:n-1]
|
2015-04-03 23:00:46 +00:00
|
|
|
return true
|
2015-04-03 22:59:30 +00:00
|
|
|
}
|
|
|
|
}
|
2015-04-03 23:00:46 +00:00
|
|
|
return false
|
2015-04-03 22:59:30 +00:00
|
|
|
}
|
|
|
|
|
2015-03-11 22:19:41 +00:00
|
|
|
// MountEntry is used to represent a mount table entry
|
|
|
|
type MountEntry struct {
|
2015-04-02 01:04:36 +00:00
|
|
|
Path string `json:"path"` // Mount Path
|
|
|
|
Type string `json:"type"` // Logical backend Type
|
|
|
|
Description string `json:"description"` // User-provided description
|
|
|
|
UUID string `json:"uuid"` // Barrier view UUID
|
2015-08-29 13:02:46 +00:00
|
|
|
Config MountConfig `json:"config"` // Configuration related to this mount (but not backend-derived)
|
2015-08-28 21:25:09 +00:00
|
|
|
Options map[string]string `json:"options"` // Backend options
|
2015-04-02 01:04:36 +00:00
|
|
|
Tainted bool `json:"tainted,omitempty"` // Set as a Write-Ahead flag for unmount/remount
|
2015-03-11 22:19:41 +00:00
|
|
|
}
|
|
|
|
|
2015-08-29 13:02:46 +00:00
|
|
|
// MountConfig is used to hold settable options
|
|
|
|
type MountConfig struct {
|
2015-08-31 18:27:49 +00:00
|
|
|
DefaultLeaseTTL time.Duration `json:"default_lease_ttl" structs:"default_lease_ttl"` // Override for global default
|
|
|
|
MaxLeaseTTL time.Duration `json:"max_lease_ttl" structs:"max_lease_ttl"` // Override for global default
|
2015-08-28 21:25:09 +00:00
|
|
|
}
|
|
|
|
|
2015-03-12 01:19:40 +00:00
|
|
|
// Returns a deep copy of the mount entry
|
|
|
|
func (e *MountEntry) Clone() *MountEntry {
|
2015-03-31 20:14:08 +00:00
|
|
|
optClone := make(map[string]string)
|
|
|
|
for k, v := range e.Options {
|
|
|
|
optClone[k] = v
|
|
|
|
}
|
2015-03-12 01:19:40 +00:00
|
|
|
return &MountEntry{
|
|
|
|
Path: e.Path,
|
|
|
|
Type: e.Type,
|
|
|
|
Description: e.Description,
|
|
|
|
UUID: e.UUID,
|
2015-08-28 21:25:09 +00:00
|
|
|
Config: e.Config,
|
2015-03-31 20:14:08 +00:00
|
|
|
Options: optClone,
|
2015-03-12 01:19:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-15 00:26:59 +00:00
|
|
|
// Mount is used to mount a new backend to the mount table.
|
2015-03-15 01:31:31 +00:00
|
|
|
func (c *Core) mount(me *MountEntry) error {
|
2015-03-17 22:28:01 +00:00
|
|
|
c.mounts.Lock()
|
|
|
|
defer c.mounts.Unlock()
|
2015-03-12 01:19:40 +00:00
|
|
|
|
|
|
|
// Ensure we end the path in a slash
|
|
|
|
if !strings.HasSuffix(me.Path, "/") {
|
|
|
|
me.Path += "/"
|
|
|
|
}
|
|
|
|
|
2015-08-10 17:27:25 +00:00
|
|
|
// Prevent protected paths from being mounted
|
2015-03-18 22:16:52 +00:00
|
|
|
for _, p := range protectedMounts {
|
|
|
|
if strings.HasPrefix(me.Path, p) {
|
2015-08-10 17:27:25 +00:00
|
|
|
return logical.CodedError(403, fmt.Sprintf("cannot mount '%s'", me.Path))
|
2015-03-18 22:16:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-12 01:19:40 +00:00
|
|
|
// Verify there is no conflicting mount
|
|
|
|
if match := c.router.MatchingMount(me.Path); match != "" {
|
2015-08-10 17:27:25 +00:00
|
|
|
return logical.CodedError(409, fmt.Sprintf("existing mount at %s", match))
|
2015-03-12 01:19:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Generate a new UUID and view
|
2015-06-30 19:38:32 +00:00
|
|
|
me.UUID = uuid.GenerateUUID()
|
2015-03-12 01:19:40 +00:00
|
|
|
view := NewBarrierView(c.barrier, backendBarrierPrefix+me.UUID+"/")
|
|
|
|
|
2015-07-01 00:30:43 +00:00
|
|
|
// Create the new backend
|
2015-08-28 21:25:09 +00:00
|
|
|
sysView, err := c.MountEntrySysView(me)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
backend, err := c.newLogicalBackend(me.Type, sysView, view, nil)
|
2015-07-01 00:30:43 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-03-12 01:19:40 +00:00
|
|
|
// Update the mount table
|
|
|
|
newTable := c.mounts.Clone()
|
|
|
|
newTable.Entries = append(newTable.Entries, me)
|
|
|
|
if err := c.persistMounts(newTable); err != nil {
|
|
|
|
return errors.New("failed to update mount table")
|
|
|
|
}
|
|
|
|
c.mounts = newTable
|
|
|
|
|
|
|
|
// Mount the backend
|
2015-04-03 21:42:39 +00:00
|
|
|
if err := c.router.Mount(backend, me.Path, me.UUID, view); err != nil {
|
2015-03-12 01:19:40 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
c.logger.Printf("[INFO] core: mounted '%s' type: %s", me.Path, me.Type)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
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-15 00:26:59 +00:00
|
|
|
// Unmount is used to unmount a path.
|
2015-03-15 01:31:31 +00:00
|
|
|
func (c *Core) unmount(path string) error {
|
2015-03-17 22:28:01 +00:00
|
|
|
c.mounts.Lock()
|
|
|
|
defer c.mounts.Unlock()
|
2015-03-12 01:19:40 +00:00
|
|
|
|
|
|
|
// Ensure we end the path in a slash
|
|
|
|
if !strings.HasSuffix(path, "/") {
|
|
|
|
path += "/"
|
|
|
|
}
|
|
|
|
|
2015-03-18 22:16:52 +00:00
|
|
|
// Prevent protected paths from being unmounted
|
|
|
|
for _, p := range protectedMounts {
|
|
|
|
if strings.HasPrefix(path, p) {
|
|
|
|
return fmt.Errorf("cannot unmount '%s'", path)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-12 01:19:40 +00:00
|
|
|
// Verify exact match of the route
|
|
|
|
match := c.router.MatchingMount(path)
|
|
|
|
if match == "" || path != match {
|
|
|
|
return fmt.Errorf("no matching mount")
|
|
|
|
}
|
|
|
|
|
2015-04-02 18:17:55 +00:00
|
|
|
// Store the view for this backend
|
|
|
|
view := c.router.MatchingView(path)
|
|
|
|
|
2015-04-02 01:04:36 +00:00
|
|
|
// Mark the entry as tainted
|
|
|
|
if err := c.taintMountEntry(path); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-04-02 18:17:55 +00:00
|
|
|
// Taint the router path to prevent routing
|
|
|
|
if err := c.router.Taint(path); err != nil {
|
2015-04-02 01:04:36 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-04-02 18:17:55 +00:00
|
|
|
// Invoke the rollback manager a final time
|
|
|
|
if err := c.rollback.Rollback(path); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-04-02 05:13:08 +00:00
|
|
|
|
2015-04-02 18:17:55 +00:00
|
|
|
// Revoke all the dynamic keys
|
|
|
|
if err := c.expiration.RevokePrefix(path); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-04-02 05:13:08 +00:00
|
|
|
|
2015-04-02 18:17:55 +00:00
|
|
|
// Unmount the backend entirely
|
|
|
|
if err := c.router.Unmount(path); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clear the data in the view
|
|
|
|
if err := ClearView(view); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-04-02 05:13:08 +00:00
|
|
|
|
|
|
|
// Remove the mount table entry
|
|
|
|
if err := c.removeMountEntry(path); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-04-02 01:04:36 +00:00
|
|
|
c.logger.Printf("[INFO] core: unmounted '%s'", path)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// removeMountEntry is used to remove an entry from the mount table
|
|
|
|
func (c *Core) removeMountEntry(path string) error {
|
2015-03-12 01:19:40 +00:00
|
|
|
// Remove the entry from the mount table
|
|
|
|
newTable := c.mounts.Clone()
|
2015-04-03 22:59:30 +00:00
|
|
|
newTable.Remove(path)
|
2015-03-12 01:19:40 +00:00
|
|
|
|
|
|
|
// Update the mount table
|
|
|
|
if err := c.persistMounts(newTable); err != nil {
|
|
|
|
return errors.New("failed to update mount table")
|
|
|
|
}
|
|
|
|
c.mounts = newTable
|
2015-04-02 01:04:36 +00:00
|
|
|
return nil
|
|
|
|
}
|
2015-03-12 01:19:40 +00:00
|
|
|
|
2015-04-02 01:04:36 +00:00
|
|
|
// taintMountEntry is used to mark an entry in the mount table as tainted
|
|
|
|
func (c *Core) taintMountEntry(path string) error {
|
|
|
|
// Remove the entry from the mount table
|
|
|
|
newTable := c.mounts.Clone()
|
2015-04-03 22:59:30 +00:00
|
|
|
newTable.SetTaint(path, true)
|
2015-03-12 01:19:40 +00:00
|
|
|
|
2015-04-02 01:04:36 +00:00
|
|
|
// Update the mount table
|
|
|
|
if err := c.persistMounts(newTable); err != nil {
|
|
|
|
return errors.New("failed to update mount table")
|
|
|
|
}
|
|
|
|
c.mounts = newTable
|
2015-03-12 01:19:40 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
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-15 00:26:59 +00:00
|
|
|
// Remount is used to remount a path at a new mount point.
|
2015-08-31 18:27:49 +00:00
|
|
|
func (c *Core) remount(src, dst string, config *MountConfig) error {
|
2015-03-17 22:28:01 +00:00
|
|
|
c.mounts.Lock()
|
|
|
|
defer c.mounts.Unlock()
|
2015-03-12 19:09:30 +00:00
|
|
|
|
|
|
|
// Ensure we end the path in a slash
|
|
|
|
if !strings.HasSuffix(src, "/") {
|
|
|
|
src += "/"
|
|
|
|
}
|
|
|
|
if !strings.HasSuffix(dst, "/") {
|
|
|
|
dst += "/"
|
|
|
|
}
|
|
|
|
|
2015-03-18 22:16:52 +00:00
|
|
|
// Prevent protected paths from being remounted
|
2015-03-12 19:09:30 +00:00
|
|
|
for _, p := range protectedMounts {
|
2015-03-18 22:16:52 +00:00
|
|
|
if strings.HasPrefix(src, p) {
|
|
|
|
return fmt.Errorf("cannot remount '%s'", src)
|
2015-03-12 19:09:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify exact match of the route
|
|
|
|
match := c.router.MatchingMount(src)
|
|
|
|
if match == "" || src != match {
|
|
|
|
return fmt.Errorf("no matching mount at '%s'", src)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify there is no conflicting mount
|
|
|
|
if match := c.router.MatchingMount(dst); match != "" {
|
|
|
|
return fmt.Errorf("existing mount at '%s'", match)
|
|
|
|
}
|
|
|
|
|
2015-04-02 19:03:00 +00:00
|
|
|
// Mark the entry as tainted
|
|
|
|
if err := c.taintMountEntry(src); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Taint the router path to prevent routing
|
|
|
|
if err := c.router.Taint(src); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Invoke the rollback manager a final time
|
|
|
|
if err := c.rollback.Rollback(src); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Revoke all the dynamic keys
|
|
|
|
if err := c.expiration.RevokePrefix(src); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-03-12 19:09:30 +00:00
|
|
|
// Update the entry in the mount table
|
|
|
|
newTable := c.mounts.Clone()
|
|
|
|
for _, ent := range newTable.Entries {
|
|
|
|
if ent.Path == src {
|
|
|
|
ent.Path = dst
|
2015-04-02 19:03:00 +00:00
|
|
|
ent.Tainted = false
|
2015-08-31 18:27:49 +00:00
|
|
|
if config != nil {
|
|
|
|
ent.Config = *config
|
|
|
|
}
|
2015-03-12 19:09:30 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the mount table
|
|
|
|
if err := c.persistMounts(newTable); err != nil {
|
|
|
|
return errors.New("failed to update mount table")
|
|
|
|
}
|
|
|
|
c.mounts = newTable
|
|
|
|
|
|
|
|
// Remount the backend
|
|
|
|
if err := c.router.Remount(src, dst); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-04-02 19:03:00 +00:00
|
|
|
|
|
|
|
// Un-taint the path
|
|
|
|
if err := c.router.Untaint(dst); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-03-12 19:09:30 +00:00
|
|
|
c.logger.Printf("[INFO] core: remounted '%s' to '%s'", src, dst)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
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-15 00:26:59 +00:00
|
|
|
// loadMounts is invoked as part of postUnseal to load the mount table
|
|
|
|
func (c *Core) loadMounts() error {
|
|
|
|
// Load the existing mount table
|
|
|
|
raw, err := c.barrier.Get(coreMountConfigPath)
|
|
|
|
if err != nil {
|
|
|
|
c.logger.Printf("[ERR] core: failed to read mount table: %v", err)
|
2015-08-28 21:25:09 +00:00
|
|
|
return errLoadMountsFailed
|
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-15 00:26:59 +00:00
|
|
|
}
|
|
|
|
if raw != nil {
|
|
|
|
c.mounts = &MountTable{}
|
|
|
|
if err := json.Unmarshal(raw.Value, c.mounts); err != nil {
|
|
|
|
c.logger.Printf("[ERR] core: failed to decode mount table: %v", err)
|
2015-08-28 21:25:09 +00:00
|
|
|
return errLoadMountsFailed
|
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-15 00:26:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Done if we have restored the mount table
|
|
|
|
if c.mounts != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create and persist the default mount table
|
|
|
|
c.mounts = defaultMountTable()
|
|
|
|
if err := c.persistMounts(c.mounts); err != nil {
|
2015-08-28 21:25:09 +00:00
|
|
|
return errLoadMountsFailed
|
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-15 00:26:59 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// persistMounts is used to persist the mount table after modification
|
|
|
|
func (c *Core) persistMounts(table *MountTable) error {
|
|
|
|
// Marshal the table
|
|
|
|
raw, err := json.Marshal(table)
|
|
|
|
if err != nil {
|
|
|
|
c.logger.Printf("[ERR] core: failed to encode mount table: %v", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create an entry
|
|
|
|
entry := &Entry{
|
|
|
|
Key: coreMountConfigPath,
|
|
|
|
Value: raw,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write to the physical backend
|
|
|
|
if err := c.barrier.Put(entry); err != nil {
|
|
|
|
c.logger.Printf("[ERR] core: failed to persist mount table: %v", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// setupMounts is invoked after we've loaded the mount table to
|
|
|
|
// initialize the logical backends and setup the router
|
|
|
|
func (c *Core) setupMounts() error {
|
2015-03-15 21:53:41 +00:00
|
|
|
var backend logical.Backend
|
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-15 00:26:59 +00:00
|
|
|
var view *BarrierView
|
|
|
|
for _, entry := range c.mounts.Entries {
|
|
|
|
// Initialize the backend, special casing for system
|
2015-04-02 00:24:22 +00:00
|
|
|
barrierPath := backendBarrierPrefix + entry.UUID + "/"
|
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-15 00:26:59 +00:00
|
|
|
if entry.Type == "system" {
|
2015-04-02 00:24:22 +00:00
|
|
|
barrierPath = systemBarrierPrefix
|
2015-03-15 23:25:38 +00:00
|
|
|
}
|
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-15 00:26:59 +00:00
|
|
|
|
2015-07-01 00:30:43 +00:00
|
|
|
// Create a barrier view using the UUID
|
|
|
|
view = NewBarrierView(c.barrier, barrierPath)
|
|
|
|
|
|
|
|
// Initialize the backend
|
2015-08-28 21:25:09 +00:00
|
|
|
// Create the new backend
|
|
|
|
sysView, err := c.MountEntrySysView(entry)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
backend, err = c.newLogicalBackend(entry.Type, sysView, view, nil)
|
2015-03-15 23:25:38 +00:00
|
|
|
if err != nil {
|
|
|
|
c.logger.Printf(
|
|
|
|
"[ERR] core: failed to create mount entry %#v: %v",
|
|
|
|
entry, err)
|
2015-08-28 21:25:09 +00:00
|
|
|
return errLoadMountsFailed
|
2015-03-15 23:25:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if entry.Type == "system" {
|
|
|
|
c.systemView = view
|
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-15 00:26:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Mount the backend
|
2015-04-03 21:42:39 +00:00
|
|
|
err = c.router.Mount(backend, entry.Path, entry.UUID, view)
|
2015-03-15 23:25:38 +00:00
|
|
|
if err != nil {
|
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-15 00:26:59 +00:00
|
|
|
c.logger.Printf("[ERR] core: failed to mount entry %#v: %v", entry, err)
|
2015-08-28 21:25:09 +00:00
|
|
|
return errLoadMountsFailed
|
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-15 00:26:59 +00:00
|
|
|
}
|
2015-04-02 18:17:55 +00:00
|
|
|
|
|
|
|
// Ensure the path is tainted if set in the mount table
|
|
|
|
if entry.Tainted {
|
|
|
|
c.router.Taint(entry.Path)
|
|
|
|
}
|
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-15 00:26:59 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// unloadMounts is used before we seal the vault to reset the mounts to
|
|
|
|
// their unloaded state. This is reversed by load and setup mounts.
|
|
|
|
func (c *Core) unloadMounts() error {
|
|
|
|
c.mounts = nil
|
|
|
|
c.router = NewRouter()
|
|
|
|
c.systemView = nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-03-18 22:46:07 +00:00
|
|
|
// newLogicalBackend is used to create and configure a new logical backend by name
|
2015-08-28 21:25:09 +00:00
|
|
|
func (c *Core) newLogicalBackend(t string, sysView logical.SystemView, view logical.Storage, conf map[string]string) (logical.Backend, error) {
|
2015-03-18 22:21:41 +00:00
|
|
|
f, ok := c.logicalBackends[t]
|
2015-03-15 23:25:38 +00:00
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("unknown backend type: %s", t)
|
|
|
|
}
|
|
|
|
|
2015-07-01 00:30:43 +00:00
|
|
|
config := &logical.BackendConfig{
|
|
|
|
View: view,
|
|
|
|
Logger: c.logger,
|
|
|
|
Config: conf,
|
2015-08-28 21:25:09 +00:00
|
|
|
System: sysView,
|
2015-07-01 00:30:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
b, err := f(config)
|
2015-04-04 18:39:58 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return b, nil
|
2015-03-15 23:25:38 +00:00
|
|
|
}
|
|
|
|
|
2015-08-28 21:25:09 +00:00
|
|
|
// MountEntrySysView creates a logical.SystemView from global and
|
|
|
|
// mount-specific entries
|
|
|
|
func (c *Core) MountEntrySysView(me *MountEntry) (logical.SystemView, error) {
|
|
|
|
if me == nil {
|
2015-08-29 13:02:46 +00:00
|
|
|
return nil, fmt.Errorf("[ERR] core: nil MountEntry when generating SystemView")
|
2015-08-28 21:25:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sysView := &logical.StaticSystemView{
|
|
|
|
DefaultLeaseTTLVal: c.defaultLeaseTTL,
|
|
|
|
MaxLeaseTTLVal: c.maxLeaseTTL,
|
|
|
|
}
|
|
|
|
|
|
|
|
if me.Config.DefaultLeaseTTL != 0 {
|
|
|
|
sysView.DefaultLeaseTTLVal = me.Config.DefaultLeaseTTL
|
|
|
|
}
|
|
|
|
if me.Config.MaxLeaseTTL != 0 {
|
|
|
|
sysView.MaxLeaseTTLVal = me.Config.MaxLeaseTTL
|
|
|
|
}
|
|
|
|
|
|
|
|
return sysView, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// PathSysView is a simple helper for MountEntrySysView
|
|
|
|
func (c *Core) PathSysView(path string) (logical.SystemView, error) {
|
|
|
|
pathSep := strings.IndexRune(path, '/')
|
|
|
|
if pathSep == -1 {
|
|
|
|
return nil, fmt.Errorf("[ERR] core: failed to find separator for path %s", path)
|
|
|
|
}
|
|
|
|
me := c.mounts.Find(path[0 : pathSep+1])
|
|
|
|
if me == nil {
|
|
|
|
me = c.auth.Find(path[0 : pathSep+1])
|
|
|
|
}
|
|
|
|
if me == nil {
|
|
|
|
me = c.audit.Find(path[0 : pathSep+1])
|
|
|
|
}
|
|
|
|
if me == nil {
|
|
|
|
return nil, fmt.Errorf("[ERR] core: failed to find mount entry for path %s", path)
|
|
|
|
}
|
2015-08-29 13:02:46 +00:00
|
|
|
return c.MountEntrySysView(me)
|
2015-08-28 21:25:09 +00:00
|
|
|
}
|
|
|
|
|
2015-03-11 22:19:41 +00:00
|
|
|
// defaultMountTable creates a default mount table
|
|
|
|
func defaultMountTable() *MountTable {
|
|
|
|
table := &MountTable{}
|
|
|
|
genericMount := &MountEntry{
|
|
|
|
Path: "secret/",
|
|
|
|
Type: "generic",
|
|
|
|
Description: "generic secret storage",
|
2015-06-30 19:38:32 +00:00
|
|
|
UUID: uuid.GenerateUUID(),
|
2015-03-11 22:19:41 +00:00
|
|
|
}
|
|
|
|
sysMount := &MountEntry{
|
|
|
|
Path: "sys/",
|
|
|
|
Type: "system",
|
|
|
|
Description: "system endpoints used for control, policy and debugging",
|
2015-06-30 19:38:32 +00:00
|
|
|
UUID: uuid.GenerateUUID(),
|
2015-03-11 22:19:41 +00:00
|
|
|
}
|
|
|
|
table.Entries = append(table.Entries, genericMount)
|
|
|
|
table.Entries = append(table.Entries, sysMount)
|
|
|
|
return table
|
|
|
|
}
|