2015-03-11 22:19:41 +00:00
package vault
import (
2018-01-19 06:44:44 +00:00
"context"
2015-03-11 22:19:41 +00:00
"errors"
2015-03-12 01:19:40 +00:00
"fmt"
2017-02-18 18:51:05 +00:00
"sort"
2015-03-12 01:19:40 +00:00
"strings"
2018-03-02 17:18:39 +00:00
"sync"
2015-08-28 21:25:09 +00:00
"time"
2015-03-15 21:53:41 +00:00
2015-12-16 17:56:20 +00:00
"github.com/hashicorp/go-uuid"
2017-05-08 14:23:29 +00:00
"github.com/hashicorp/vault/helper/consts"
2016-07-06 16:25:40 +00:00
"github.com/hashicorp/vault/helper/jsonutil"
2017-05-05 21:20:30 +00:00
"github.com/hashicorp/vault/helper/strutil"
2015-03-15 21:53:41 +00:00
"github.com/hashicorp/vault/logical"
2017-10-23 21:15:56 +00:00
"github.com/mitchellh/copystructure"
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
2017-02-17 01:13:19 +00:00
// coreLocalMountConfigPath is used to store mount configuration for local
// (non-replicated) mounts
coreLocalMountConfigPath = "core/local-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/"
2016-05-26 16:55:00 +00:00
2016-05-26 17:38:51 +00:00
// mountTableType is the value we expect to find for the mount table and
// corresponding entries
2016-05-26 16:55:00 +00:00
mountTableType = "mounts"
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-09-10 01:58:09 +00:00
"cubbyhole/" ,
2017-10-11 17:21:20 +00:00
"identity/" ,
2015-09-10 01:58:09 +00:00
}
2015-09-19 15:50:50 +00:00
untunableMounts = [ ] string {
"cubbyhole/" ,
"sys/" ,
"audit/" ,
2017-10-11 17:21:20 +00:00
"identity/" ,
2015-09-19 15:50:50 +00:00
}
2015-09-10 01:58:09 +00:00
// singletonMounts can only exist in one location and are
// loaded by default. These are types, not paths.
singletonMounts = [ ] string {
"cubbyhole" ,
"system" ,
2017-05-05 20:45:48 +00:00
"token" ,
2017-10-11 17:21:20 +00:00
"identity" ,
2015-03-12 19:09:30 +00:00
}
2017-09-15 13:02:29 +00:00
// mountAliases maps old backend names to new backend names, allowing us
// to move/rename backends but maintain backwards compatibility
mountAliases = map [ string ] string { "generic" : "kv" }
2015-03-11 22:19:41 +00:00
)
2017-10-23 19:35:28 +00:00
func collectBackendLocalPaths ( backend logical . Backend , viewPath string ) [ ] string {
if backend == nil || backend . SpecialPaths ( ) == nil || len ( backend . SpecialPaths ( ) . LocalStorage ) == 0 {
return nil
}
var paths [ ] string
for _ , path := range backend . SpecialPaths ( ) . LocalStorage {
paths = append ( paths , viewPath + path )
}
return paths
}
2017-06-26 17:14:36 +00:00
func ( c * Core ) generateMountAccessor ( entryType string ) ( string , error ) {
var accessor string
for {
randBytes , err := uuid . GenerateRandomBytes ( 4 )
if err != nil {
return "" , err
}
accessor = fmt . Sprintf ( "%s_%s" , entryType , fmt . Sprintf ( "%08x" , randBytes [ 0 : 4 ] ) )
if entry := c . router . MatchingMountByAccessor ( accessor ) ; entry == nil {
break
}
}
return accessor , nil
}
2015-03-11 22:19:41 +00:00
// MountTable is used to represent the internal mount table
type MountTable struct {
2016-05-26 16:55:00 +00:00
Type string ` json:"type" `
2015-03-11 22:19:41 +00:00
Entries [ ] * MountEntry ` json:"entries" `
}
2016-09-13 15:50:14 +00:00
// shallowClone returns a copy of the mount table that
2015-09-10 02:17:49 +00:00
// keeps the MountEntry locations, so as not to invalidate
// other locations holding pointers. Care needs to be taken
// if modifying entries rather than modifying the table itself
2016-09-13 15:50:14 +00:00
func ( t * MountTable ) shallowClone ( ) * MountTable {
2015-03-12 01:19:40 +00:00
mt := & MountTable {
2016-05-26 16:55:00 +00:00
Type : t . Type ,
2015-03-12 01:19:40 +00:00
Entries : make ( [ ] * MountEntry , len ( t . Entries ) ) ,
}
for i , e := range t . Entries {
2015-09-10 02:17:49 +00:00
mt . Entries [ i ] = e
2015-03-12 01:19:40 +00:00
}
return mt
}
2016-09-13 15:50:14 +00:00
// setTaint is used to set the taint on given entry
2017-03-02 19:37:59 +00:00
func ( t * MountTable ) setTaint ( path string , value bool ) * MountEntry {
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
2017-03-02 19:37:59 +00:00
return t . Entries [ i ]
2015-04-03 22:59:30 +00:00
}
}
2017-03-02 19:37:59 +00:00
return nil
2015-04-03 22:59:30 +00:00
}
2016-09-30 19:04:50 +00:00
// remove is used to remove a given path entry; returns the entry that was
// removed
func ( t * MountTable ) remove ( path string ) * MountEntry {
2015-04-03 22:59:30 +00:00
n := len ( t . Entries )
for i := 0 ; i < n ; i ++ {
2016-09-30 19:04:50 +00:00
if entry := t . Entries [ i ] ; entry . Path == path {
2015-04-03 22:59:30 +00:00
t . Entries [ i ] , t . Entries [ n - 1 ] = t . Entries [ n - 1 ] , nil
t . Entries = t . Entries [ : n - 1 ]
2016-09-30 19:04:50 +00:00
return entry
2015-04-03 22:59:30 +00:00
}
}
2016-09-30 19:04:50 +00:00
return nil
2015-04-03 22:59:30 +00:00
}
2017-02-18 18:51:05 +00:00
// sortEntriesByPath sorts the entries in the table by path and returns the
// table; this is useful for tests
func ( t * MountTable ) sortEntriesByPath ( ) * MountTable {
sort . Slice ( t . Entries , func ( i , j int ) bool {
return t . Entries [ i ] . Path < t . Entries [ j ] . Path
} )
return t
}
2015-03-11 22:19:41 +00:00
// MountEntry is used to represent a mount table entry
type MountEntry struct {
2016-05-26 16:55:00 +00:00
Table string ` json:"table" ` // The table it belongs to
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
2017-06-26 17:14:36 +00:00
Accessor string ` json:"accessor" ` // Unique but more human-friendly ID. Does not change, not used for any sensitive things (like as a salt, which the UUID sometimes is).
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
2017-02-17 01:13:19 +00:00
Local bool ` json:"local" ` // Local mounts are not replicated or affected by replication
2017-11-13 16:22:22 +00:00
SealWrap bool ` json:"seal_wrap" ` // Whether to wrap CSPs
2015-04-02 01:04:36 +00:00
Tainted bool ` json:"tainted,omitempty" ` // Set as a Write-Ahead flag for unmount/remount
2018-03-02 17:18:39 +00:00
// synthesizedConfigCache is used to cache configuration values
synthesizedConfigCache sync . Map
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 {
2018-03-02 17:18:39 +00:00
DefaultLeaseTTL time . Duration ` json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl" ` // Override for global default
MaxLeaseTTL time . Duration ` json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl" ` // Override for global default
ForceNoCache bool ` json:"force_no_cache" structs:"force_no_cache" mapstructure:"force_no_cache" ` // Override for global default
PluginName string ` json:"plugin_name,omitempty" structs:"plugin_name,omitempty" mapstructure:"plugin_name" `
AuditNonHMACRequestKeys [ ] string ` json:"audit_non_hmac_request_keys,omitempty" structs:"audit_non_hmac_request_keys" mapstructure:"audit_non_hmac_request_keys" `
AuditNonHMACResponseKeys [ ] string ` json:"audit_non_hmac_response_keys,omitempty" structs:"audit_non_hmac_response_keys" mapstructure:"audit_non_hmac_response_keys" `
Backend plugin system (#2874)
* Add backend plugin changes
* Fix totp backend plugin tests
* Fix logical/plugin InvalidateKey test
* Fix plugin catalog CRUD test, fix NoopBackend
* Clean up commented code block
* Fix system backend mount test
* Set plugin_name to omitempty, fix handleMountTable config parsing
* Clean up comments, keep shim connections alive until cleanup
* Include pluginClient, disallow LookupPlugin call from within a plugin
* Add wrapper around backendPluginClient for proper cleanup
* Add logger shim tests
* Add logger, storage, and system shim tests
* Use pointer receivers for system view shim
* Use plugin name if no path is provided on mount
* Enable plugins for auth backends
* Add backend type attribute, move builtin/plugin/package
* Fix merge conflict
* Fix missing plugin name in mount config
* Add integration tests on enabling auth backend plugins
* Remove dependency cycle on mock-plugin
* Add passthrough backend plugin, use logical.BackendType to determine lease generation
* Remove vault package dependency on passthrough package
* Add basic impl test for passthrough plugin
* Incorporate feedback; set b.backend after shims creation on backendPluginServer
* Fix totp plugin test
* Add plugin backends docs
* Fix tests
* Fix builtin/plugin tests
* Remove flatten from PluginRunner fields
* Move mock plugin to logical/plugin, remove totp and passthrough plugins
* Move pluginMap into newPluginClient
* Do not create storage RPC connection on HandleRequest and HandleExistenceCheck
* Change shim logger's Fatal to no-op
* Change BackendType to uint32, match UX backend types
* Change framework.Backend Setup signature
* Add Setup func to logical.Backend interface
* Move OptionallyEnableMlock call into plugin.Serve, update docs and comments
* Remove commented var in plugin package
* RegisterLicense on logical.Backend interface (#3017)
* Add RegisterLicense to logical.Backend interface
* Update RegisterLicense to use callback func on framework.Backend
* Refactor framework.Backend.RegisterLicense
* plugin: Prevent plugin.SystemViewClient.ResponseWrapData from getting JWTs
* plugin: Revert BackendType to remove TypePassthrough and related references
* Fix typo in plugin backends docs
2017-07-20 17:28:40 +00:00
}
// APIMountConfig is an embedded struct of api.MountConfigInput
type APIMountConfig struct {
2018-03-02 17:18:39 +00:00
DefaultLeaseTTL string ` json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl" `
MaxLeaseTTL string ` json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl" `
ForceNoCache bool ` json:"force_no_cache" structs:"force_no_cache" mapstructure:"force_no_cache" `
PluginName string ` json:"plugin_name,omitempty" structs:"plugin_name,omitempty" mapstructure:"plugin_name" `
AuditNonHMACRequestKeys [ ] string ` json:"audit_non_hmac_request_keys,omitempty" structs:"audit_non_hmac_request_keys" mapstructure:"audit_non_hmac_request_keys" `
AuditNonHMACResponseKeys [ ] string ` json:"audit_non_hmac_response_keys,omitempty" structs:"audit_non_hmac_response_keys" mapstructure:"audit_non_hmac_response_keys" `
2017-10-23 19:35:28 +00:00
}
// Clone returns a deep copy of the mount entry
func ( e * MountEntry ) Clone ( ) ( * MountEntry , error ) {
cp , err := copystructure . Copy ( e )
if err != nil {
return nil , err
}
return cp . ( * MountEntry ) , nil
2015-08-28 21:25:09 +00:00
}
2018-03-02 17:18:39 +00:00
// SyncCache syncs tunable configuration values to the cache
func ( e * MountEntry ) SyncCache ( ) {
if len ( e . Config . AuditNonHMACRequestKeys ) == 0 {
e . synthesizedConfigCache . Delete ( "audit_non_hmac_request_keys" )
} else {
e . synthesizedConfigCache . Store ( "audit_non_hmac_request_keys" , e . Config . AuditNonHMACRequestKeys )
}
if len ( e . Config . AuditNonHMACResponseKeys ) == 0 {
e . synthesizedConfigCache . Delete ( "audit_non_hmac_response_keys" )
} else {
e . synthesizedConfigCache . Store ( "audit_non_hmac_response_keys" , e . Config . AuditNonHMACResponseKeys )
}
}
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.
2018-01-19 06:44:44 +00:00
func ( c * Core ) mount ( ctx context . Context , entry * MountEntry ) error {
2015-03-12 01:19:40 +00:00
// Ensure we end the path in a slash
2017-02-17 01:13:19 +00:00
if ! strings . HasSuffix ( entry . Path , "/" ) {
entry . Path += "/"
2015-03-12 01:19:40 +00:00
}
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 {
2017-02-17 01:13:19 +00:00
if strings . HasPrefix ( entry . Path , p ) {
return logical . CodedError ( 403 , fmt . Sprintf ( "cannot mount '%s'" , entry . Path ) )
2015-03-18 22:16:52 +00:00
}
}
2015-09-10 01:58:09 +00:00
// Do not allow more than one instance of a singleton mount
for _ , p := range singletonMounts {
2017-02-17 01:13:19 +00:00
if entry . Type == p {
return logical . CodedError ( 403 , fmt . Sprintf ( "Cannot mount more than one instance of '%s'" , entry . Type ) )
2015-09-10 01:58:09 +00:00
}
}
2018-01-19 06:44:44 +00:00
return c . mountInternal ( ctx , entry )
2017-10-23 19:35:28 +00:00
}
2015-09-10 01:58:09 +00:00
2018-01-19 06:44:44 +00:00
func ( c * Core ) mountInternal ( ctx context . Context , entry * MountEntry ) error {
2017-01-17 18:02:29 +00:00
c . mountsLock . Lock ( )
defer c . mountsLock . Unlock ( )
2017-11-06 20:29:09 +00:00
// Verify there are no conflicting mounts
if match := c . router . MountConflict ( entry . 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
2017-02-17 01:13:19 +00:00
if entry . UUID == "" {
entryUUID , err := uuid . GenerateUUID ( )
if err != nil {
return err
}
entry . UUID = entryUUID
}
2017-06-26 17:14:36 +00:00
if entry . Accessor == "" {
accessor , err := c . generateMountAccessor ( entry . Type )
if err != nil {
return err
}
entry . Accessor = accessor
}
2018-03-02 17:18:39 +00:00
// Sync values to the cache
entry . SyncCache ( )
2017-02-17 01:13:19 +00:00
viewPath := backendBarrierPrefix + entry . UUID + "/"
view := NewBarrierView ( c . barrier , viewPath )
2018-02-09 19:04:25 +00:00
// Mark the view as read-only until the mounting is complete and
// ensure that it is reset after. This ensures that there will be no
// writes during the construction of the backend.
view . setReadOnlyErr ( logical . ErrSetupReadOnly )
defer view . setReadOnlyErr ( nil )
2017-10-23 19:35:28 +00:00
var backend logical . Backend
var err error
2017-02-17 01:13:19 +00:00
sysView := c . mountEntrySysView ( entry )
Backend plugin system (#2874)
* Add backend plugin changes
* Fix totp backend plugin tests
* Fix logical/plugin InvalidateKey test
* Fix plugin catalog CRUD test, fix NoopBackend
* Clean up commented code block
* Fix system backend mount test
* Set plugin_name to omitempty, fix handleMountTable config parsing
* Clean up comments, keep shim connections alive until cleanup
* Include pluginClient, disallow LookupPlugin call from within a plugin
* Add wrapper around backendPluginClient for proper cleanup
* Add logger shim tests
* Add logger, storage, and system shim tests
* Use pointer receivers for system view shim
* Use plugin name if no path is provided on mount
* Enable plugins for auth backends
* Add backend type attribute, move builtin/plugin/package
* Fix merge conflict
* Fix missing plugin name in mount config
* Add integration tests on enabling auth backend plugins
* Remove dependency cycle on mock-plugin
* Add passthrough backend plugin, use logical.BackendType to determine lease generation
* Remove vault package dependency on passthrough package
* Add basic impl test for passthrough plugin
* Incorporate feedback; set b.backend after shims creation on backendPluginServer
* Fix totp plugin test
* Add plugin backends docs
* Fix tests
* Fix builtin/plugin tests
* Remove flatten from PluginRunner fields
* Move mock plugin to logical/plugin, remove totp and passthrough plugins
* Move pluginMap into newPluginClient
* Do not create storage RPC connection on HandleRequest and HandleExistenceCheck
* Change shim logger's Fatal to no-op
* Change BackendType to uint32, match UX backend types
* Change framework.Backend Setup signature
* Add Setup func to logical.Backend interface
* Move OptionallyEnableMlock call into plugin.Serve, update docs and comments
* Remove commented var in plugin package
* RegisterLicense on logical.Backend interface (#3017)
* Add RegisterLicense to logical.Backend interface
* Update RegisterLicense to use callback func on framework.Backend
* Refactor framework.Backend.RegisterLicense
* plugin: Prevent plugin.SystemViewClient.ResponseWrapData from getting JWTs
* plugin: Revert BackendType to remove TypePassthrough and related references
* Fix typo in plugin backends docs
2017-07-20 17:28:40 +00:00
conf := make ( map [ string ] string )
if entry . Config . PluginName != "" {
conf [ "plugin_name" ] = entry . Config . PluginName
}
2017-02-17 01:13:19 +00:00
2017-10-23 19:35:28 +00:00
// Consider having plugin name under entry.Options
2018-01-19 06:44:44 +00:00
backend , err = c . newLogicalBackend ( ctx , entry . Type , sysView , view , conf )
2016-01-13 18:40:08 +00:00
if err != nil {
return err
}
2017-03-04 21:35:41 +00:00
if backend == nil {
return fmt . Errorf ( "nil backend of type %q returned from creation function" , entry . Type )
}
2015-03-12 01:19:40 +00:00
Backend plugin system (#2874)
* Add backend plugin changes
* Fix totp backend plugin tests
* Fix logical/plugin InvalidateKey test
* Fix plugin catalog CRUD test, fix NoopBackend
* Clean up commented code block
* Fix system backend mount test
* Set plugin_name to omitempty, fix handleMountTable config parsing
* Clean up comments, keep shim connections alive until cleanup
* Include pluginClient, disallow LookupPlugin call from within a plugin
* Add wrapper around backendPluginClient for proper cleanup
* Add logger shim tests
* Add logger, storage, and system shim tests
* Use pointer receivers for system view shim
* Use plugin name if no path is provided on mount
* Enable plugins for auth backends
* Add backend type attribute, move builtin/plugin/package
* Fix merge conflict
* Fix missing plugin name in mount config
* Add integration tests on enabling auth backend plugins
* Remove dependency cycle on mock-plugin
* Add passthrough backend plugin, use logical.BackendType to determine lease generation
* Remove vault package dependency on passthrough package
* Add basic impl test for passthrough plugin
* Incorporate feedback; set b.backend after shims creation on backendPluginServer
* Fix totp plugin test
* Add plugin backends docs
* Fix tests
* Fix builtin/plugin tests
* Remove flatten from PluginRunner fields
* Move mock plugin to logical/plugin, remove totp and passthrough plugins
* Move pluginMap into newPluginClient
* Do not create storage RPC connection on HandleRequest and HandleExistenceCheck
* Change shim logger's Fatal to no-op
* Change BackendType to uint32, match UX backend types
* Change framework.Backend Setup signature
* Add Setup func to logical.Backend interface
* Move OptionallyEnableMlock call into plugin.Serve, update docs and comments
* Remove commented var in plugin package
* RegisterLicense on logical.Backend interface (#3017)
* Add RegisterLicense to logical.Backend interface
* Update RegisterLicense to use callback func on framework.Backend
* Refactor framework.Backend.RegisterLicense
* plugin: Prevent plugin.SystemViewClient.ResponseWrapData from getting JWTs
* plugin: Revert BackendType to remove TypePassthrough and related references
* Fix typo in plugin backends docs
2017-07-20 17:28:40 +00:00
// Check for the correct backend type
backendType := backend . Type ( )
if entry . Type == "plugin" && backendType != logical . TypeLogical {
return fmt . Errorf ( "cannot mount '%s' of type '%s' as a logical backend" , entry . Config . PluginName , backendType )
}
2017-10-11 17:21:20 +00:00
c . setCoreBackend ( entry , backend , view )
2016-09-13 15:50:14 +00:00
newTable := c . mounts . shallowClone ( )
2017-02-17 01:13:19 +00:00
newTable . Entries = append ( newTable . Entries , entry )
2018-01-19 06:44:44 +00:00
if err := c . persistMounts ( ctx , newTable , entry . Local ) ; err != nil {
2017-01-12 01:21:34 +00:00
c . logger . Error ( "core: failed to update mount table" , "error" , err )
2016-08-04 13:11:24 +00:00
return logical . CodedError ( 500 , "failed to update mount table" )
2015-03-12 01:19:40 +00:00
}
c . mounts = newTable
2017-02-17 01:13:19 +00:00
if err := c . router . Mount ( backend , entry . Path , entry , view ) ; err != nil {
2017-01-17 20:15:28 +00:00
return err
}
2016-08-19 20:45:17 +00:00
if c . logger . IsInfo ( ) {
2017-02-17 01:13:19 +00:00
c . logger . Info ( "core: successful mount" , "path" , entry . Path , "type" , entry . Type )
2016-08-19 20:45:17 +00:00
}
2015-03-12 01:19:40 +00:00
return nil
}
2016-09-19 17:02:25 +00:00
// Unmount is used to unmount a path. The boolean indicates whether the mount
// was found.
2018-01-19 06:44:44 +00:00
func ( c * Core ) unmount ( ctx context . Context , path string ) error {
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 ) {
2017-07-13 17:57:14 +00:00
return fmt . Errorf ( "cannot unmount '%s'" , path )
2015-03-18 22:16:52 +00:00
}
}
2018-01-19 06:44:44 +00:00
return c . unmountInternal ( ctx , path )
2017-10-23 19:35:28 +00:00
}
2015-03-18 22:16:52 +00:00
2018-01-19 06:44:44 +00:00
func ( c * Core ) unmountInternal ( ctx context . Context , path string ) error {
2015-03-12 01:19:40 +00:00
// Verify exact match of the route
2015-09-11 23:49:20 +00:00
match := c . router . MatchingMount ( path )
if match == "" || path != match {
2017-07-13 17:57:14 +00:00
return fmt . Errorf ( "no matching mount" )
2015-03-12 01:19:40 +00:00
}
2016-09-13 15:50:14 +00:00
// Get the view for this backend
2017-10-23 19:35:28 +00:00
view := c . router . MatchingStorageByAPIPath ( path )
// Get the backend/mount entry for this path, used to remove ignored
// replication prefixes
backend := c . router . MatchingBackend ( path )
entry := c . router . MatchingMountEntry ( path )
2015-04-02 18:17:55 +00:00
2015-04-02 01:04:36 +00:00
// Mark the entry as tainted
2018-01-19 06:44:44 +00:00
if err := c . taintMountEntry ( ctx , path ) ; err != nil {
2017-10-23 19:35:28 +00:00
c . logger . Error ( "core: failed to taint mount entry for path being unmounted" , "error" , err , "path" , path )
2017-07-13 17:57:14 +00:00
return err
2015-04-02 01:04:36 +00:00
}
2016-09-13 15:50:14 +00:00
// Taint the router path to prevent routing. Note that in-flight requests
// are uncertain, right now.
2015-04-02 18:17:55 +00:00
if err := c . router . Taint ( path ) ; err != nil {
2017-07-13 17:57:14 +00:00
return err
2015-04-02 01:04:36 +00:00
}
2017-10-23 19:35:28 +00:00
if backend != nil {
// 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
2017-10-23 19:35:28 +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
2017-10-23 19:35:28 +00:00
// Call cleanup function if it exists
2018-01-19 06:44:44 +00:00
backend . Cleanup ( ctx )
2017-02-01 19:05:25 +00:00
}
2015-04-02 18:17:55 +00:00
// Unmount the backend entirely
2018-01-19 06:44:44 +00:00
if err := c . router . Unmount ( ctx , path ) ; err != nil {
2017-07-13 17:57:14 +00:00
return err
2015-04-02 18:17:55 +00:00
}
2017-10-23 19:35:28 +00:00
switch {
2018-01-16 18:51:55 +00:00
case entry . Local , ! c . ReplicationState ( ) . HasState ( consts . ReplicationPerformanceSecondary ) :
2017-10-23 19:35:28 +00:00
// Have writable storage, remove the whole thing
2018-01-19 06:44:44 +00:00
if err := logical . ClearView ( ctx , view ) ; err != nil {
2017-10-23 19:35:28 +00:00
c . logger . Error ( "core: failed to clear view for path being unmounted" , "error" , err , "path" , path )
return err
}
2015-04-02 18:17:55 +00:00
}
2015-04-02 05:13:08 +00:00
// Remove the mount table entry
2018-01-19 06:44:44 +00:00
if err := c . removeMountEntry ( ctx , path ) ; err != nil {
2017-10-23 19:35:28 +00:00
c . logger . Error ( "core: failed to remove mount entry for path being unmounted" , "error" , err , "path" , path )
2017-07-13 17:57:14 +00:00
return err
2015-04-02 05:13:08 +00:00
}
2017-10-23 19:35:28 +00:00
2016-08-19 20:45:17 +00:00
if c . logger . IsInfo ( ) {
2017-02-01 19:05:25 +00:00
c . logger . Info ( "core: successfully unmounted" , "path" , path )
2016-08-19 20:45:17 +00:00
}
2017-07-13 17:57:14 +00:00
return nil
2015-04-02 01:04:36 +00:00
}
// removeMountEntry is used to remove an entry from the mount table
2018-01-19 06:44:44 +00:00
func ( c * Core ) removeMountEntry ( ctx context . Context , path string ) error {
2016-09-13 15:50:14 +00:00
c . mountsLock . Lock ( )
defer c . mountsLock . Unlock ( )
2015-03-12 01:19:40 +00:00
// Remove the entry from the mount table
2016-09-13 15:50:14 +00:00
newTable := c . mounts . shallowClone ( )
2017-03-02 19:37:59 +00:00
entry := newTable . remove ( path )
if entry == nil {
c . logger . Error ( "core: nil entry found removing entry in mounts table" , "path" , path )
return logical . CodedError ( 500 , "failed to remove entry in mounts table" )
}
2015-03-12 01:19:40 +00:00
2017-02-17 01:13:19 +00:00
// When unmounting all entries the JSON code will load back up from storage
// as a nil slice, which kills tests...just set it nil explicitly
if len ( newTable . Entries ) == 0 {
newTable . Entries = nil
}
2015-03-12 01:19:40 +00:00
// Update the mount table
2018-01-19 06:44:44 +00:00
if err := c . persistMounts ( ctx , newTable , entry . Local ) ; err != nil {
2017-03-02 19:37:59 +00:00
c . logger . Error ( "core: failed to remove entry from mounts table" , "error" , err )
return logical . CodedError ( 500 , "failed to remove entry from mounts table" )
2015-03-12 01:19:40 +00:00
}
2015-11-11 16:44:07 +00:00
2015-03-12 01:19:40 +00:00
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
2018-01-19 06:44:44 +00:00
func ( c * Core ) taintMountEntry ( ctx context . Context , path string ) error {
2016-09-13 15:50:14 +00:00
c . mountsLock . Lock ( )
defer c . mountsLock . Unlock ( )
2015-11-11 16:44:07 +00:00
// As modifying the taint of an entry affects shallow clones,
// we simply use the original
2017-03-02 19:37:59 +00:00
entry := c . mounts . setTaint ( path , true )
if entry == nil {
c . logger . Error ( "core: nil entry found tainting entry in mounts table" , "path" , path )
return logical . CodedError ( 500 , "failed to taint entry in mounts table" )
}
2015-03-12 01:19:40 +00:00
2015-04-02 01:04:36 +00:00
// Update the mount table
2018-01-19 06:44:44 +00:00
if err := c . persistMounts ( ctx , c . mounts , entry . Local ) ; err != nil {
2017-03-02 19:37:59 +00:00
c . logger . Error ( "core: failed to taint entry in mounts table" , "error" , err )
return logical . CodedError ( 500 , "failed to taint entry in mounts table" )
2015-04-02 01:04:36 +00:00
}
2015-11-11 16:44:07 +00:00
2015-03-12 01:19:40 +00:00
return nil
}
2017-10-23 19:35:28 +00:00
// remountForce takes a copy of the mount entry for the path and fully unmounts
// and remounts the backend to pick up any changes, such as filtered paths
2018-01-19 06:44:44 +00:00
func ( c * Core ) remountForce ( ctx context . Context , path string ) error {
2017-10-23 19:35:28 +00:00
me := c . router . MatchingMountEntry ( path )
if me == nil {
return fmt . Errorf ( "cannot find mount for path '%s'" , path )
}
me , err := me . Clone ( )
if err != nil {
return err
}
2018-01-19 06:44:44 +00:00
if err := c . unmount ( ctx , path ) ; err != nil {
2017-10-23 19:35:28 +00:00
return err
}
2018-01-19 06:44:44 +00:00
return c . mount ( ctx , me )
2017-10-23 19:35:28 +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
// Remount is used to remount a path at a new mount point.
2018-01-19 06:44:44 +00:00
func ( c * Core ) remount ( ctx context . Context , src , dst string ) error {
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
2015-09-11 23:49:20 +00:00
match := c . router . MatchingMount ( src )
if match == "" || src != match {
2015-03-12 19:09:30 +00:00
return fmt . Errorf ( "no matching mount at '%s'" , src )
}
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
2018-01-19 06:44:44 +00:00
if err := c . taintMountEntry ( ctx , src ) ; err != nil {
2015-04-02 19:03:00 +00:00
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
}
2016-09-13 15:50:14 +00:00
c . mountsLock . Lock ( )
2017-10-23 19:35:28 +00:00
var entry * MountEntry
for _ , entry = range c . mounts . Entries {
if entry . Path == src {
entry . Path = dst
entry . Tainted = false
2015-03-12 19:09:30 +00:00
break
}
}
2017-10-23 19:35:28 +00:00
if entry == nil {
c . mountsLock . Unlock ( )
2017-03-02 19:37:59 +00:00
c . logger . Error ( "core: failed to find entry in mounts table" )
return logical . CodedError ( 500 , "failed to find entry in mounts table" )
}
2015-03-12 19:09:30 +00:00
// Update the mount table
2018-01-19 06:44:44 +00:00
if err := c . persistMounts ( ctx , c . mounts , entry . Local ) ; err != nil {
2017-10-23 19:35:28 +00:00
entry . Path = src
entry . Tainted = true
2016-09-13 15:50:14 +00:00
c . mountsLock . Unlock ( )
2017-03-02 19:37:59 +00:00
c . logger . Error ( "core: failed to update mounts table" , "error" , err )
return logical . CodedError ( 500 , "failed to update mounts table" )
2015-03-12 19:09:30 +00:00
}
2016-09-13 15:50:14 +00:00
c . mountsLock . Unlock ( )
2015-03-12 19:09:30 +00:00
// 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
}
2016-08-19 20:45:17 +00:00
if c . logger . IsInfo ( ) {
c . logger . Info ( "core: successful remount" , "old_path" , src , "new_path" , dst )
}
2015-03-12 19:09:30 +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
// loadMounts is invoked as part of postUnseal to load the mount table
2018-01-19 06:44:44 +00:00
func ( c * Core ) loadMounts ( ctx context . Context ) error {
2015-11-11 16:44:07 +00:00
mountTable := & MountTable { }
2017-02-17 01:13:19 +00:00
localMountTable := & MountTable { }
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
// Load the existing mount table
2018-01-19 06:44:44 +00:00
raw , err := c . barrier . Get ( ctx , coreMountConfigPath )
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 err != nil {
2016-08-19 20:45:17 +00:00
c . logger . Error ( "core: failed to read mount table" , "error" , 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
}
2018-01-19 06:44:44 +00:00
rawLocal , err := c . barrier . Get ( ctx , coreLocalMountConfigPath )
2017-02-17 01:13:19 +00:00
if err != nil {
c . logger . Error ( "core: failed to read local mount table" , "error" , err )
return errLoadMountsFailed
}
2015-11-11 16:44:07 +00:00
c . mountsLock . Lock ( )
defer c . mountsLock . Unlock ( )
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 {
2016-08-04 21:20:37 +00:00
// Check if the persisted value has canary in the beginning. If
// yes, decompress the table and then JSON decode it. If not,
// simply JSON decode it.
2016-08-09 14:33:41 +00:00
if err := jsonutil . DecodeJSON ( raw . Value , mountTable ) ; err != nil {
2016-08-19 20:45:17 +00:00
c . logger . Error ( "core: failed to decompress and/or decode the mount table" , "error" , err )
2016-08-04 21:20:37 +00:00
return err
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-11-11 16:44:07 +00:00
c . mounts = mountTable
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
}
2017-11-08 01:30:02 +00:00
var needPersist bool
if c . mounts == nil {
c . mounts = c . defaultMountTable ( )
needPersist = true
}
2017-02-17 01:13:19 +00:00
if rawLocal != nil {
if err := jsonutil . DecodeJSON ( rawLocal . Value , localMountTable ) ; err != nil {
c . logger . Error ( "core: failed to decompress and/or decode the local mount table" , "error" , err )
return err
}
2017-11-07 23:04:37 +00:00
if localMountTable != nil && len ( localMountTable . Entries ) > 0 {
c . mounts . Entries = append ( c . mounts . Entries , localMountTable . Entries ... )
}
2017-02-17 01:13:19 +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
2017-11-08 01:30:02 +00:00
// Note that this is only designed to work with singletons, as it checks by
// type only.
2016-05-26 16:55:00 +00:00
2017-11-08 01:30:02 +00:00
// Upgrade to typed mount table
if c . mounts . Type == "" {
c . mounts . Type = mountTableType
needPersist = true
}
2016-05-26 16:55:00 +00:00
2017-11-08 01:30:02 +00:00
for _ , requiredMount := range c . requiredMountTable ( ) . Entries {
foundRequired := false
for _ , coreMount := range c . mounts . Entries {
if coreMount . Type == requiredMount . Type {
foundRequired = true
break
2015-09-21 21:54:36 +00:00
}
2017-11-08 01:30:02 +00:00
}
2017-10-23 19:35:28 +00:00
2017-11-08 01:30:02 +00:00
// In a replication scenario we will let sync invalidation take
// care of creating a new required mount that doesn't exist yet.
// This should only happen in the upgrade case where a new one is
// introduced on the primary; otherwise initial bootstrapping will
// ensure this comes over. If we upgrade first, we simply don't
// create the mount, so we won't conflict when we sync. If this is
// local (e.g. cubbyhole) we do still add it.
2018-01-16 18:51:55 +00:00
if ! foundRequired && ( ! c . ReplicationState ( ) . HasState ( consts . ReplicationPerformanceSecondary ) || requiredMount . Local ) {
2017-11-08 01:30:02 +00:00
c . mounts . Entries = append ( c . mounts . Entries , requiredMount )
needPersist = true
2015-09-21 21:54:36 +00:00
}
2017-11-08 01:30:02 +00:00
}
2015-09-21 21:54:36 +00:00
2017-11-08 01:30:02 +00:00
// Upgrade to table-scoped entries
for _ , entry := range c . mounts . Entries {
if entry . Type == "cubbyhole" && ! entry . Local {
entry . Local = true
needPersist = true
}
if entry . Table == "" {
entry . Table = c . mounts . Type
needPersist = true
}
if entry . Accessor == "" {
accessor , err := c . generateMountAccessor ( entry . Type )
if err != nil {
return err
2017-06-26 17:14:36 +00:00
}
2017-11-08 01:30:02 +00:00
entry . Accessor = accessor
needPersist = true
2016-05-26 16:55:00 +00:00
}
2018-03-02 17:18:39 +00:00
// Sync values to the cache
entry . SyncCache ( )
2017-11-08 01:30:02 +00:00
}
2016-05-26 16:55:00 +00:00
2017-11-08 01:30:02 +00:00
// Done if we have restored the mount table and we don't need
// to persist
if ! needPersist {
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
}
2018-01-19 06:44:44 +00:00
if err := c . persistMounts ( ctx , c . mounts , false ) ; err != nil {
2017-01-12 01:21:34 +00:00
c . logger . Error ( "core: failed to persist mount table" , "error" , 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
}
return nil
}
// persistMounts is used to persist the mount table after modification
2018-01-19 06:44:44 +00:00
func ( c * Core ) persistMounts ( ctx context . Context , table * MountTable , localOnly bool ) error {
2016-05-26 16:55:00 +00:00
if table . Type != mountTableType {
2016-08-19 20:45:17 +00:00
c . logger . Error ( "core: given table to persist has wrong type" , "actual_type" , table . Type , "expected_type" , mountTableType )
2016-05-26 16:55:00 +00:00
return fmt . Errorf ( "invalid table type given, not persisting" )
}
for _ , entry := range table . Entries {
if entry . Table != table . Type {
2016-08-19 20:45:17 +00:00
c . logger . Error ( "core: given entry to persist in mount table has wrong table value" , "path" , entry . Path , "entry_table_type" , entry . Table , "actual_type" , table . Type )
2016-05-26 16:55:00 +00:00
return fmt . Errorf ( "invalid mount entry found, not persisting" )
}
}
2017-02-17 01:13:19 +00:00
nonLocalMounts := & MountTable {
Type : mountTableType ,
}
localMounts := & MountTable {
Type : mountTableType ,
}
for _ , entry := range table . Entries {
if entry . Local {
localMounts . Entries = append ( localMounts . Entries , entry )
} else {
nonLocalMounts . Entries = append ( nonLocalMounts . Entries , entry )
}
}
2017-03-02 19:37:59 +00:00
if ! localOnly {
// Encode the mount table into JSON and compress it (lzw).
compressedBytes , err := jsonutil . EncodeJSONAndCompress ( nonLocalMounts , nil )
if err != nil {
c . logger . Error ( "core: failed to encode and/or compress the mount table" , "error" , err )
return err
}
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
2017-03-02 19:37:59 +00:00
// Create an entry
entry := & Entry {
Key : coreMountConfigPath ,
Value : compressedBytes ,
}
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
2017-03-02 19:37:59 +00:00
// Write to the physical backend
2018-01-19 06:44:44 +00:00
if err := c . barrier . Put ( ctx , entry ) ; err != nil {
2017-03-02 19:37:59 +00:00
c . logger . Error ( "core: failed to persist mount table" , "error" , err )
return err
}
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
}
2017-02-17 01:13:19 +00:00
// Repeat with local mounts
2017-03-02 19:37:59 +00:00
compressedBytes , err := jsonutil . EncodeJSONAndCompress ( localMounts , nil )
2017-02-17 01:13:19 +00:00
if err != nil {
c . logger . Error ( "core: failed to encode and/or compress the local mount table" , "error" , err )
return err
}
2017-03-02 19:37:59 +00:00
entry := & Entry {
2017-02-17 01:13:19 +00:00
Key : coreLocalMountConfigPath ,
Value : compressedBytes ,
}
2018-01-19 06:44:44 +00:00
if err := c . barrier . Put ( ctx , entry ) ; err != nil {
2017-02-17 01:13:19 +00:00
c . logger . Error ( "core: failed to persist local mount table" , "error" , err )
return err
}
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
}
// setupMounts is invoked after we've loaded the mount table to
// initialize the logical backends and setup the router
2018-01-19 06:44:44 +00:00
func ( c * Core ) setupMounts ( ctx context . Context ) error {
2015-11-11 16:44:07 +00:00
c . mountsLock . Lock ( )
defer c . mountsLock . Unlock ( )
2017-10-23 21:15:56 +00:00
var backendType logical . BackendType
2015-11-11 16:44:07 +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
for _ , entry := range c . mounts . Entries {
2017-09-01 05:02:03 +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
// 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
2018-02-09 20:39:27 +00:00
view := NewBarrierView ( c . barrier , barrierPath )
2017-10-23 19:35:28 +00:00
2018-02-09 19:04:25 +00:00
// Mark the view as read-only until the mounting is complete and
// ensure that it is reset after. This ensures that there will be no
// writes during the construction of the backend.
view . setReadOnlyErr ( logical . ErrSetupReadOnly )
2018-02-09 20:39:27 +00:00
defer view . setReadOnlyErr ( nil )
2018-02-09 19:04:25 +00:00
2017-10-23 19:35:28 +00:00
var backend logical . Backend
var err error
2017-02-17 01:13:19 +00:00
sysView := c . mountEntrySysView ( entry )
Backend plugin system (#2874)
* Add backend plugin changes
* Fix totp backend plugin tests
* Fix logical/plugin InvalidateKey test
* Fix plugin catalog CRUD test, fix NoopBackend
* Clean up commented code block
* Fix system backend mount test
* Set plugin_name to omitempty, fix handleMountTable config parsing
* Clean up comments, keep shim connections alive until cleanup
* Include pluginClient, disallow LookupPlugin call from within a plugin
* Add wrapper around backendPluginClient for proper cleanup
* Add logger shim tests
* Add logger, storage, and system shim tests
* Use pointer receivers for system view shim
* Use plugin name if no path is provided on mount
* Enable plugins for auth backends
* Add backend type attribute, move builtin/plugin/package
* Fix merge conflict
* Fix missing plugin name in mount config
* Add integration tests on enabling auth backend plugins
* Remove dependency cycle on mock-plugin
* Add passthrough backend plugin, use logical.BackendType to determine lease generation
* Remove vault package dependency on passthrough package
* Add basic impl test for passthrough plugin
* Incorporate feedback; set b.backend after shims creation on backendPluginServer
* Fix totp plugin test
* Add plugin backends docs
* Fix tests
* Fix builtin/plugin tests
* Remove flatten from PluginRunner fields
* Move mock plugin to logical/plugin, remove totp and passthrough plugins
* Move pluginMap into newPluginClient
* Do not create storage RPC connection on HandleRequest and HandleExistenceCheck
* Change shim logger's Fatal to no-op
* Change BackendType to uint32, match UX backend types
* Change framework.Backend Setup signature
* Add Setup func to logical.Backend interface
* Move OptionallyEnableMlock call into plugin.Serve, update docs and comments
* Remove commented var in plugin package
* RegisterLicense on logical.Backend interface (#3017)
* Add RegisterLicense to logical.Backend interface
* Update RegisterLicense to use callback func on framework.Backend
* Refactor framework.Backend.RegisterLicense
* plugin: Prevent plugin.SystemViewClient.ResponseWrapData from getting JWTs
* plugin: Revert BackendType to remove TypePassthrough and related references
* Fix typo in plugin backends docs
2017-07-20 17:28:40 +00:00
// Set up conf to pass in plugin_name
conf := make ( map [ string ] string )
if entry . Config . PluginName != "" {
conf [ "plugin_name" ] = entry . Config . PluginName
}
2015-08-28 21:25:09 +00:00
// Create the new backend
2018-01-19 06:44:44 +00:00
backend , err = c . newLogicalBackend ( ctx , entry . Type , sysView , view , conf )
2015-03-15 23:25:38 +00:00
if err != nil {
2016-08-19 20:45:17 +00:00
c . logger . Error ( "core: failed to create mount entry" , "path" , entry . Path , "error" , err )
2017-12-15 18:31:57 +00:00
if entry . Type == "plugin" {
// If we encounter an error instantiating the backend due to an error,
// skip backend initialization but register the entry to the mount table
// to preserve storage and path.
c . logger . Warn ( "core: skipping plugin-based mount entry" , "path" , entry . Path )
2017-09-01 05:02:03 +00:00
goto ROUTER_MOUNT
}
2015-08-28 21:25:09 +00:00
return errLoadMountsFailed
2015-03-15 23:25:38 +00:00
}
2017-03-04 21:35:41 +00:00
if backend == nil {
return fmt . Errorf ( "created mount entry of type %q is nil" , entry . Type )
}
2015-03-15 23:25:38 +00:00
Backend plugin system (#2874)
* Add backend plugin changes
* Fix totp backend plugin tests
* Fix logical/plugin InvalidateKey test
* Fix plugin catalog CRUD test, fix NoopBackend
* Clean up commented code block
* Fix system backend mount test
* Set plugin_name to omitempty, fix handleMountTable config parsing
* Clean up comments, keep shim connections alive until cleanup
* Include pluginClient, disallow LookupPlugin call from within a plugin
* Add wrapper around backendPluginClient for proper cleanup
* Add logger shim tests
* Add logger, storage, and system shim tests
* Use pointer receivers for system view shim
* Use plugin name if no path is provided on mount
* Enable plugins for auth backends
* Add backend type attribute, move builtin/plugin/package
* Fix merge conflict
* Fix missing plugin name in mount config
* Add integration tests on enabling auth backend plugins
* Remove dependency cycle on mock-plugin
* Add passthrough backend plugin, use logical.BackendType to determine lease generation
* Remove vault package dependency on passthrough package
* Add basic impl test for passthrough plugin
* Incorporate feedback; set b.backend after shims creation on backendPluginServer
* Fix totp plugin test
* Add plugin backends docs
* Fix tests
* Fix builtin/plugin tests
* Remove flatten from PluginRunner fields
* Move mock plugin to logical/plugin, remove totp and passthrough plugins
* Move pluginMap into newPluginClient
* Do not create storage RPC connection on HandleRequest and HandleExistenceCheck
* Change shim logger's Fatal to no-op
* Change BackendType to uint32, match UX backend types
* Change framework.Backend Setup signature
* Add Setup func to logical.Backend interface
* Move OptionallyEnableMlock call into plugin.Serve, update docs and comments
* Remove commented var in plugin package
* RegisterLicense on logical.Backend interface (#3017)
* Add RegisterLicense to logical.Backend interface
* Update RegisterLicense to use callback func on framework.Backend
* Refactor framework.Backend.RegisterLicense
* plugin: Prevent plugin.SystemViewClient.ResponseWrapData from getting JWTs
* plugin: Revert BackendType to remove TypePassthrough and related references
* Fix typo in plugin backends docs
2017-07-20 17:28:40 +00:00
// Check for the correct backend type
2017-10-23 21:15:56 +00:00
backendType = backend . Type ( )
2017-10-23 19:35:28 +00:00
if entry . Type == "plugin" && backendType != logical . TypeLogical {
return fmt . Errorf ( "cannot mount '%s' of type '%s' as a logical backend" , entry . Config . PluginName , backendType )
Backend plugin system (#2874)
* Add backend plugin changes
* Fix totp backend plugin tests
* Fix logical/plugin InvalidateKey test
* Fix plugin catalog CRUD test, fix NoopBackend
* Clean up commented code block
* Fix system backend mount test
* Set plugin_name to omitempty, fix handleMountTable config parsing
* Clean up comments, keep shim connections alive until cleanup
* Include pluginClient, disallow LookupPlugin call from within a plugin
* Add wrapper around backendPluginClient for proper cleanup
* Add logger shim tests
* Add logger, storage, and system shim tests
* Use pointer receivers for system view shim
* Use plugin name if no path is provided on mount
* Enable plugins for auth backends
* Add backend type attribute, move builtin/plugin/package
* Fix merge conflict
* Fix missing plugin name in mount config
* Add integration tests on enabling auth backend plugins
* Remove dependency cycle on mock-plugin
* Add passthrough backend plugin, use logical.BackendType to determine lease generation
* Remove vault package dependency on passthrough package
* Add basic impl test for passthrough plugin
* Incorporate feedback; set b.backend after shims creation on backendPluginServer
* Fix totp plugin test
* Add plugin backends docs
* Fix tests
* Fix builtin/plugin tests
* Remove flatten from PluginRunner fields
* Move mock plugin to logical/plugin, remove totp and passthrough plugins
* Move pluginMap into newPluginClient
* Do not create storage RPC connection on HandleRequest and HandleExistenceCheck
* Change shim logger's Fatal to no-op
* Change BackendType to uint32, match UX backend types
* Change framework.Backend Setup signature
* Add Setup func to logical.Backend interface
* Move OptionallyEnableMlock call into plugin.Serve, update docs and comments
* Remove commented var in plugin package
* RegisterLicense on logical.Backend interface (#3017)
* Add RegisterLicense to logical.Backend interface
* Update RegisterLicense to use callback func on framework.Backend
* Refactor framework.Backend.RegisterLicense
* plugin: Prevent plugin.SystemViewClient.ResponseWrapData from getting JWTs
* plugin: Revert BackendType to remove TypePassthrough and related references
* Fix typo in plugin backends docs
2017-07-20 17:28:40 +00:00
}
2017-10-11 17:21:20 +00:00
c . setCoreBackend ( entry , backend , view )
2017-09-01 05:02:03 +00:00
ROUTER_MOUNT :
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-09-04 20:58:12 +00:00
err = c . router . Mount ( backend , entry . Path , entry , view )
2015-03-15 23:25:38 +00:00
if err != nil {
2016-08-19 20:45:17 +00:00
c . logger . Error ( "core: failed to mount entry" , "path" , entry . Path , "error" , err )
2015-08-28 21:25:09 +00:00
return errLoadMountsFailed
Backend plugin system (#2874)
* Add backend plugin changes
* Fix totp backend plugin tests
* Fix logical/plugin InvalidateKey test
* Fix plugin catalog CRUD test, fix NoopBackend
* Clean up commented code block
* Fix system backend mount test
* Set plugin_name to omitempty, fix handleMountTable config parsing
* Clean up comments, keep shim connections alive until cleanup
* Include pluginClient, disallow LookupPlugin call from within a plugin
* Add wrapper around backendPluginClient for proper cleanup
* Add logger shim tests
* Add logger, storage, and system shim tests
* Use pointer receivers for system view shim
* Use plugin name if no path is provided on mount
* Enable plugins for auth backends
* Add backend type attribute, move builtin/plugin/package
* Fix merge conflict
* Fix missing plugin name in mount config
* Add integration tests on enabling auth backend plugins
* Remove dependency cycle on mock-plugin
* Add passthrough backend plugin, use logical.BackendType to determine lease generation
* Remove vault package dependency on passthrough package
* Add basic impl test for passthrough plugin
* Incorporate feedback; set b.backend after shims creation on backendPluginServer
* Fix totp plugin test
* Add plugin backends docs
* Fix tests
* Fix builtin/plugin tests
* Remove flatten from PluginRunner fields
* Move mock plugin to logical/plugin, remove totp and passthrough plugins
* Move pluginMap into newPluginClient
* Do not create storage RPC connection on HandleRequest and HandleExistenceCheck
* Change shim logger's Fatal to no-op
* Change BackendType to uint32, match UX backend types
* Change framework.Backend Setup signature
* Add Setup func to logical.Backend interface
* Move OptionallyEnableMlock call into plugin.Serve, update docs and comments
* Remove commented var in plugin package
* RegisterLicense on logical.Backend interface (#3017)
* Add RegisterLicense to logical.Backend interface
* Update RegisterLicense to use callback func on framework.Backend
* Refactor framework.Backend.RegisterLicense
* plugin: Prevent plugin.SystemViewClient.ResponseWrapData from getting JWTs
* plugin: Revert BackendType to remove TypePassthrough and related references
* Fix typo in plugin backends docs
2017-07-20 17:28:40 +00:00
}
2017-10-23 19:35:28 +00:00
Backend plugin system (#2874)
* Add backend plugin changes
* Fix totp backend plugin tests
* Fix logical/plugin InvalidateKey test
* Fix plugin catalog CRUD test, fix NoopBackend
* Clean up commented code block
* Fix system backend mount test
* Set plugin_name to omitempty, fix handleMountTable config parsing
* Clean up comments, keep shim connections alive until cleanup
* Include pluginClient, disallow LookupPlugin call from within a plugin
* Add wrapper around backendPluginClient for proper cleanup
* Add logger shim tests
* Add logger, storage, and system shim tests
* Use pointer receivers for system view shim
* Use plugin name if no path is provided on mount
* Enable plugins for auth backends
* Add backend type attribute, move builtin/plugin/package
* Fix merge conflict
* Fix missing plugin name in mount config
* Add integration tests on enabling auth backend plugins
* Remove dependency cycle on mock-plugin
* Add passthrough backend plugin, use logical.BackendType to determine lease generation
* Remove vault package dependency on passthrough package
* Add basic impl test for passthrough plugin
* Incorporate feedback; set b.backend after shims creation on backendPluginServer
* Fix totp plugin test
* Add plugin backends docs
* Fix tests
* Fix builtin/plugin tests
* Remove flatten from PluginRunner fields
* Move mock plugin to logical/plugin, remove totp and passthrough plugins
* Move pluginMap into newPluginClient
* Do not create storage RPC connection on HandleRequest and HandleExistenceCheck
* Change shim logger's Fatal to no-op
* Change BackendType to uint32, match UX backend types
* Change framework.Backend Setup signature
* Add Setup func to logical.Backend interface
* Move OptionallyEnableMlock call into plugin.Serve, update docs and comments
* Remove commented var in plugin package
* RegisterLicense on logical.Backend interface (#3017)
* Add RegisterLicense to logical.Backend interface
* Update RegisterLicense to use callback func on framework.Backend
* Refactor framework.Backend.RegisterLicense
* plugin: Prevent plugin.SystemViewClient.ResponseWrapData from getting JWTs
* plugin: Revert BackendType to remove TypePassthrough and related references
* Fix typo in plugin backends docs
2017-07-20 17:28:40 +00:00
if c . logger . IsInfo ( ) {
c . logger . Info ( "core: successfully mounted backend" , "type" , entry . Type , "path" , 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
}
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
2015-09-10 14:11:37 +00:00
// their unloaded state, calling Cleanup if defined. This is reversed by load and setup mounts.
2018-01-19 06:44:44 +00:00
func ( c * Core ) unloadMounts ( ctx context . Context ) error {
2015-11-11 16:44:07 +00:00
c . mountsLock . Lock ( )
defer c . mountsLock . Unlock ( )
2015-09-10 14:11:37 +00:00
if c . mounts != nil {
2016-09-13 15:50:14 +00:00
mountTable := c . mounts . shallowClone ( )
2015-11-11 16:44:07 +00:00
for _ , e := range mountTable . Entries {
2017-03-04 21:35:41 +00:00
backend := c . router . MatchingBackend ( e . Path )
if backend != nil {
2018-01-19 06:44:44 +00:00
backend . Cleanup ( ctx )
2015-09-10 14:11:37 +00:00
}
}
}
2015-11-11 16:44:07 +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
c . mounts = nil
c . router = NewRouter ( )
2015-09-04 20:58:12 +00:00
c . systemBarrierView = 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
return nil
}
2015-03-18 22:46:07 +00:00
// newLogicalBackend is used to create and configure a new logical backend by name
2018-01-19 06:44:44 +00:00
func ( c * Core ) newLogicalBackend ( ctx context . Context , t string , sysView logical . SystemView , view logical . Storage , conf map [ string ] string ) ( logical . Backend , error ) {
2017-09-15 13:02:29 +00:00
if alias , ok := mountAliases [ t ] ; ok {
t = alias
}
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 {
2015-09-09 19:42:29 +00:00
StorageView : view ,
Logger : c . logger ,
Config : conf ,
2015-09-10 01:58:09 +00:00
System : sysView ,
2015-07-01 00:30:43 +00:00
}
2018-01-19 06:44:44 +00:00
b , err := f ( ctx , config )
2015-04-04 18:39:58 +00:00
if err != nil {
return nil , err
}
2017-03-04 21:35:41 +00:00
if b == nil {
return nil , fmt . Errorf ( "nil backend of type %q returned from factory" , t )
}
2015-04-04 18:39:58 +00:00
return b , nil
2015-03-15 23:25:38 +00:00
}
2015-09-02 19:56:58 +00:00
// mountEntrySysView creates a logical.SystemView from global and
2015-09-04 20:58:12 +00:00
// mount-specific entries; because this should be called when setting
// up a mountEntry, it doesn't check to ensure that me is not nil
2017-02-17 01:13:19 +00:00
func ( c * Core ) mountEntrySysView ( entry * MountEntry ) logical . SystemView {
2015-09-04 20:58:12 +00:00
return dynamicSystemView {
2015-09-10 02:17:49 +00:00
core : c ,
2017-02-17 01:13:19 +00:00
mountEntry : entry ,
2015-08-28 21:25:09 +00:00
}
}
2015-03-11 22:19:41 +00:00
// defaultMountTable creates a default mount table
2017-06-26 17:14:36 +00:00
func ( c * Core ) defaultMountTable ( ) * MountTable {
2016-05-26 16:55:00 +00:00
table := & MountTable {
Type : mountTableType ,
}
2016-01-13 18:40:08 +00:00
mountUUID , err := uuid . GenerateUUID ( )
if err != nil {
2017-06-26 17:14:36 +00:00
panic ( fmt . Sprintf ( "could not create default secret mount UUID: %v" , err ) )
}
2017-09-15 13:02:29 +00:00
mountAccessor , err := c . generateMountAccessor ( "kv" )
2017-06-26 17:14:36 +00:00
if err != nil {
panic ( fmt . Sprintf ( "could not generate default secret mount accessor: %v" , err ) )
2016-01-13 18:40:08 +00:00
}
2017-09-15 13:02:29 +00:00
kvMount := & MountEntry {
2016-05-26 16:55:00 +00:00
Table : mountTableType ,
2015-03-11 22:19:41 +00:00
Path : "secret/" ,
2017-09-15 13:02:29 +00:00
Type : "kv" ,
Description : "key/value secret storage" ,
2016-01-13 18:40:08 +00:00
UUID : mountUUID ,
2017-06-26 17:14:36 +00:00
Accessor : mountAccessor ,
2015-03-11 22:19:41 +00:00
}
2017-09-15 13:02:29 +00:00
table . Entries = append ( table . Entries , kvMount )
2017-06-26 17:14:36 +00:00
table . Entries = append ( table . Entries , c . requiredMountTable ( ) . Entries ... )
2015-09-21 21:54:36 +00:00
return table
}
// requiredMountTable() creates a mount table with entries required
// to be available
2017-06-26 17:14:36 +00:00
func ( c * Core ) requiredMountTable ( ) * MountTable {
2016-05-26 16:55:00 +00:00
table := & MountTable {
Type : mountTableType ,
}
2016-01-13 18:40:08 +00:00
cubbyholeUUID , err := uuid . GenerateUUID ( )
if err != nil {
panic ( fmt . Sprintf ( "could not create cubbyhole UUID: %v" , err ) )
}
2017-06-26 17:14:36 +00:00
cubbyholeAccessor , err := c . generateMountAccessor ( "cubbyhole" )
if err != nil {
panic ( fmt . Sprintf ( "could not generate cubbyhole accessor: %v" , err ) )
}
2015-09-10 01:58:09 +00:00
cubbyholeMount := & MountEntry {
2016-05-26 16:55:00 +00:00
Table : mountTableType ,
2015-09-10 01:58:09 +00:00
Path : "cubbyhole/" ,
Type : "cubbyhole" ,
Description : "per-token private secret storage" ,
2016-01-13 18:40:08 +00:00
UUID : cubbyholeUUID ,
2017-06-26 17:14:36 +00:00
Accessor : cubbyholeAccessor ,
2017-02-18 18:51:05 +00:00
Local : true ,
2016-01-13 18:40:08 +00:00
}
sysUUID , err := uuid . GenerateUUID ( )
if err != nil {
panic ( fmt . Sprintf ( "could not create sys UUID: %v" , err ) )
2015-09-10 01:58:09 +00:00
}
2017-06-26 17:14:36 +00:00
sysAccessor , err := c . generateMountAccessor ( "system" )
if err != nil {
panic ( fmt . Sprintf ( "could not generate sys accessor: %v" , err ) )
}
2015-03-11 22:19:41 +00:00
sysMount := & MountEntry {
2016-05-26 16:55:00 +00:00
Table : mountTableType ,
2015-03-11 22:19:41 +00:00
Path : "sys/" ,
Type : "system" ,
Description : "system endpoints used for control, policy and debugging" ,
2016-01-13 18:40:08 +00:00
UUID : sysUUID ,
2017-06-26 17:14:36 +00:00
Accessor : sysAccessor ,
2015-03-11 22:19:41 +00:00
}
2017-10-11 17:21:20 +00:00
identityUUID , err := uuid . GenerateUUID ( )
if err != nil {
panic ( fmt . Sprintf ( "could not create identity mount entry UUID: %v" , err ) )
}
identityAccessor , err := c . generateMountAccessor ( "identity" )
if err != nil {
panic ( fmt . Sprintf ( "could not generate identity accessor: %v" , err ) )
}
identityMount := & MountEntry {
Table : mountTableType ,
Path : "identity/" ,
Type : "identity" ,
Description : "identity store" ,
UUID : identityUUID ,
Accessor : identityAccessor ,
}
2015-09-10 01:58:09 +00:00
table . Entries = append ( table . Entries , cubbyholeMount )
2015-03-11 22:19:41 +00:00
table . Entries = append ( table . Entries , sysMount )
2017-10-11 17:21:20 +00:00
table . Entries = append ( table . Entries , identityMount )
2015-03-11 22:19:41 +00:00
return table
}
2017-05-05 21:20:30 +00:00
2017-05-08 17:39:18 +00:00
// This function returns tables that are singletons. The main usage of this is
// for replication, so we can send over mount info (especially, UUIDs of
// mounts, which are used for salts) for mounts that may not be able to be
// handled normally. After saving these values on the secondary, we let normal
2017-05-09 12:36:10 +00:00
// sync invalidation do its thing. Because of its use for replication, we
// exclude local mounts.
2017-05-05 21:20:30 +00:00
func ( c * Core ) singletonMountTables ( ) ( mounts , auth * MountTable ) {
mounts = & MountTable { }
auth = & MountTable { }
c . mountsLock . RLock ( )
for _ , entry := range c . mounts . Entries {
2017-05-09 12:36:10 +00:00
if strutil . StrListContains ( singletonMounts , entry . Type ) && ! entry . Local {
2017-05-05 21:20:30 +00:00
mounts . Entries = append ( mounts . Entries , entry )
}
}
c . mountsLock . RUnlock ( )
c . authLock . RLock ( )
for _ , entry := range c . auth . Entries {
2017-05-09 12:36:10 +00:00
if strutil . StrListContains ( singletonMounts , entry . Type ) && ! entry . Local {
2017-05-05 21:20:30 +00:00
auth . Entries = append ( auth . Entries , entry )
}
}
c . authLock . RUnlock ( )
return
}
2017-10-11 17:21:20 +00:00
func ( c * Core ) setCoreBackend ( entry * MountEntry , backend logical . Backend , view * BarrierView ) {
switch entry . Type {
case "system" :
c . systemBackend = backend . ( * SystemBackend )
c . systemBarrierView = view
case "cubbyhole" :
ch := backend . ( * CubbyholeBackend )
ch . saltUUID = entry . UUID
ch . storageView = view
case "identity" :
c . identityStore = backend . ( * IdentityStore )
}
}