2015-03-18 22:30:31 +00:00
package vault
2015-03-18 22:46:07 +00:00
import (
2018-01-19 06:44:44 +00:00
"context"
2015-03-18 22:46:07 +00:00
"errors"
"fmt"
2015-03-19 16:54:57 +00:00
"strings"
2015-03-18 22:46:07 +00:00
2015-12-16 17:56:20 +00:00
"github.com/hashicorp/go-uuid"
2017-10-23 21:15:56 +00:00
"github.com/hashicorp/vault/helper/consts"
2016-07-06 16:25:40 +00:00
"github.com/hashicorp/vault/helper/jsonutil"
2015-03-31 01:07:05 +00:00
"github.com/hashicorp/vault/logical"
2015-03-18 22:46:07 +00:00
)
const (
// coreAuthConfigPath is used to store the auth configuration.
// Auth configuration is protected within the Vault itself, which means it
// can only be viewed or modified after an unseal.
coreAuthConfigPath = "core/auth"
2017-02-17 04:09:39 +00:00
// coreLocalAuthConfigPath is used to store credential configuration for
// local (non-replicated) mounts
coreLocalAuthConfigPath = "core/local-auth"
2015-03-18 22:46:07 +00:00
// credentialBarrierPrefix is the prefix to the UUID used in the
// barrier view for the credential backends.
credentialBarrierPrefix = "auth/"
2015-03-19 16:56:39 +00:00
// credentialRoutePrefix is the mount prefix used for the router
credentialRoutePrefix = "auth/"
2016-05-26 17:38:51 +00:00
// credentialTableType is the value we expect to find for the credential
// table and corresponding entries
credentialTableType = "auth"
2015-03-18 22:46:07 +00:00
)
var (
2015-11-02 16:01:00 +00:00
// errLoadAuthFailed if loadCredentials encounters an error
2015-09-09 19:42:29 +00:00
errLoadAuthFailed = errors . New ( "failed to setup auth table" )
2017-04-24 19:15:50 +00:00
// credentialAliases maps old backend names to new backend names, allowing us
// to move/rename backends but maintain backwards compatibility
credentialAliases = map [ string ] string { "aws-ec2" : "aws" }
2015-03-18 22:46:07 +00:00
)
2015-03-19 02:36:17 +00:00
// enableCredential is used to enable a new credential backend
2018-01-19 06:44:44 +00:00
func ( c * Core ) enableCredential ( ctx context . Context , entry * MountEntry ) error {
2015-04-03 21:24:00 +00:00
// Ensure we end the path in a slash
if ! strings . HasSuffix ( entry . Path , "/" ) {
entry . Path += "/"
}
2015-03-19 02:36:17 +00:00
// Ensure there is a name
2015-04-03 21:24:00 +00:00
if entry . Path == "/" {
2015-03-19 16:54:57 +00:00
return fmt . Errorf ( "backend path must be specified" )
}
2015-03-19 02:36:17 +00:00
2015-11-11 16:44:07 +00:00
c . authLock . Lock ( )
defer c . authLock . Unlock ( )
2015-03-19 02:36:17 +00:00
// Look for matching name
for _ , ent := range c . auth . Entries {
2015-04-03 21:24:00 +00:00
switch {
// Existing is oauth/github/ new is oauth/ or
// existing is oauth/ and new is oauth/github/
case strings . HasPrefix ( ent . Path , entry . Path ) :
fallthrough
case strings . HasPrefix ( entry . Path , ent . Path ) :
2015-08-13 17:17:04 +00:00
return logical . CodedError ( 409 , "path is already in use" )
2015-03-19 02:36:17 +00:00
}
}
// Ensure the token backend is a singleton
if entry . Type == "token" {
return fmt . Errorf ( "token credential backend cannot be instantiated" )
}
2017-11-06 20:29:09 +00:00
if conflict := c . router . MountConflict ( credentialRoutePrefix + entry . Path ) ; conflict != "" {
return logical . CodedError ( 409 , fmt . Sprintf ( "existing mount at %s" , conflict ) )
2017-01-17 18:02:29 +00:00
}
2015-03-19 02:36:17 +00:00
// Generate a new UUID and view
2017-02-17 04:09:39 +00:00
if entry . UUID == "" {
entryUUID , err := uuid . GenerateUUID ( )
if err != nil {
return err
}
entry . UUID = entryUUID
2016-01-13 18:40:08 +00:00
}
2017-06-26 17:14:36 +00:00
if entry . Accessor == "" {
accessor , err := c . generateMountAccessor ( "auth_" + 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 04:09:39 +00:00
viewPath := credentialBarrierPrefix + 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 20:42:56 +00:00
var err error
var backend logical . Backend
2017-02-17 04:09:39 +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
}
2015-03-19 02:36:17 +00:00
2015-07-01 00:30:43 +00:00
// Create the new backend
2018-01-19 06:44:44 +00:00
backend , err = c . newCredentialBackend ( ctx , entry . Type , sysView , view , conf )
2015-07-01 00:30:43 +00:00
if err != nil {
return err
}
2017-03-04 21:35:41 +00:00
if backend == nil {
return fmt . Errorf ( "nil backend returned from %q factory" , entry . Type )
}
2015-07-01 00:30:43 +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 . TypeCredential {
2017-09-13 01:48:52 +00:00
return fmt . Errorf ( "cannot mount '%s' of type '%s' as an auth method" , 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
}
2015-03-19 02:36:17 +00:00
// Update the auth table
2016-09-13 15:50:14 +00:00
newTable := c . auth . shallowClone ( )
2015-03-19 02:36:17 +00:00
newTable . Entries = append ( newTable . Entries , entry )
2018-01-19 06:44:44 +00:00
if err := c . persistAuth ( ctx , newTable , entry . Local ) ; err != nil {
2015-03-19 02:36:17 +00:00
return errors . New ( "failed to update auth table" )
}
2015-11-11 16:44:07 +00:00
2015-03-19 02:36:17 +00:00
c . auth = newTable
2017-01-17 20:15:28 +00:00
path := credentialRoutePrefix + entry . Path
if err := c . router . Mount ( backend , path , entry , view ) ; err != nil {
return err
}
2016-08-19 20:45:17 +00:00
if c . logger . IsInfo ( ) {
c . logger . Info ( "core: enabled credential backend" , "path" , entry . Path , "type" , entry . Type )
}
2015-03-19 02:36:17 +00:00
return nil
}
2016-09-19 17:02:25 +00:00
// disableCredential is used to disable an existing credential backend; the
// boolean indicates if it existed
2018-01-19 06:44:44 +00:00
func ( c * Core ) disableCredential ( ctx context . Context , path string ) error {
2015-04-03 21:24:00 +00:00
// Ensure we end the path in a slash
if ! strings . HasSuffix ( path , "/" ) {
path += "/"
}
2015-03-19 02:36:17 +00:00
// Ensure the token backend is not affected
2015-04-03 21:24:00 +00:00
if path == "token/" {
2017-07-13 17:57:14 +00:00
return fmt . Errorf ( "token credential backend cannot be disabled" )
2015-03-19 02:36:17 +00:00
}
2015-04-03 23:07:45 +00:00
// Store the view for this backend
fullPath := credentialRoutePrefix + path
2017-10-23 20:42:56 +00:00
view := c . router . MatchingStorageByAPIPath ( fullPath )
2015-04-03 23:09:06 +00:00
if view == nil {
2017-07-13 17:57:14 +00:00
return fmt . Errorf ( "no matching backend %s" , fullPath )
2015-04-03 23:09:06 +00:00
}
2015-04-03 23:07:45 +00:00
2017-10-23 21:15:56 +00:00
// Get the backend/mount entry for this path, used to remove ignored
// replication prefixes
backend := c . router . MatchingBackend ( fullPath )
entry := c . router . MatchingMountEntry ( fullPath )
2015-04-03 23:07:45 +00:00
// Mark the entry as tainted
2018-01-19 06:44:44 +00:00
if err := c . taintCredEntry ( ctx , path ) ; err != nil {
2017-07-13 17:57:14 +00:00
return err
2015-04-03 23:07:45 +00:00
}
// Taint the router path to prevent routing
if err := c . router . Taint ( fullPath ) ; err != nil {
2017-07-13 17:57:14 +00:00
return err
2015-04-03 23:07:45 +00:00
}
2017-03-04 21:35:41 +00:00
if backend != nil {
2017-10-23 20:42:56 +00:00
// Revoke credentials from this path
if err := c . expiration . RevokePrefix ( fullPath ) ; err != nil {
return err
}
// Call cleanup function if it exists
2018-01-19 06:44:44 +00:00
backend . Cleanup ( ctx )
2017-03-04 21:35:41 +00:00
}
2015-04-03 23:07:45 +00:00
// Unmount the backend
2018-01-19 06:44:44 +00:00
if err := c . router . Unmount ( ctx , fullPath ) ; err != nil {
2017-07-13 17:57:14 +00:00
return err
2015-04-03 23:07:45 +00:00
}
2017-10-23 20:42:56 +00:00
switch {
2018-01-16 18:51:55 +00:00
case entry . Local , ! c . ReplicationState ( ) . HasState ( consts . ReplicationPerformanceSecondary ) :
2017-10-23 20:42:56 +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 20:42:56 +00:00
c . logger . Error ( "core: failed to clear view for path being unmounted" , "error" , err , "path" , path )
2017-07-13 17:57:14 +00:00
return err
2015-03-19 02:36:17 +00:00
}
2017-10-23 20:42:56 +00:00
2015-03-19 02:36:17 +00:00
}
2015-04-03 23:07:45 +00:00
// Remove the mount table entry
2018-01-19 06:44:44 +00:00
if err := c . removeCredEntry ( ctx , path ) ; err != nil {
2017-07-13 17:57:14 +00:00
return err
2015-04-03 23:07:45 +00:00
}
2016-08-19 20:45:17 +00:00
if c . logger . IsInfo ( ) {
c . logger . Info ( "core: disabled credential backend" , "path" , path )
}
2017-07-13 17:57:14 +00:00
return nil
2015-04-03 23:07:45 +00:00
}
// removeCredEntry is used to remove an entry in the auth table
2018-01-19 06:44:44 +00:00
func ( c * Core ) removeCredEntry ( ctx context . Context , path string ) error {
2017-01-17 18:02:29 +00:00
c . authLock . Lock ( )
defer c . authLock . Unlock ( )
2015-04-03 23:07:45 +00:00
// Taint the entry from the auth table
2016-09-13 15:50:14 +00:00
newTable := c . auth . 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 auth table" , "path" , path )
return logical . CodedError ( 500 , "failed to remove entry in auth table" )
}
2015-04-03 23:07:45 +00:00
// Update the auth table
2018-01-19 06:44:44 +00:00
if err := c . persistAuth ( ctx , newTable , entry . Local ) ; err != nil {
2015-04-03 23:07:45 +00:00
return errors . New ( "failed to update auth table" )
}
2015-11-11 16:44:07 +00:00
2015-04-03 23:07:45 +00:00
c . auth = newTable
2015-11-11 16:44:07 +00:00
2015-04-03 23:07:45 +00:00
return nil
}
2017-10-23 20:42:56 +00:00
// remountCredEntryForce 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 ) remountCredEntryForce ( ctx context . Context , path string ) error {
2017-10-23 20:42:56 +00:00
fullPath := credentialRoutePrefix + path
me := c . router . MatchingMountEntry ( fullPath )
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 . disableCredential ( ctx , path ) ; err != nil {
2017-10-23 20:42:56 +00:00
return err
}
2018-01-19 06:44:44 +00:00
return c . enableCredential ( ctx , me )
2017-10-23 20:42:56 +00:00
}
2015-04-03 23:07:45 +00:00
// taintCredEntry is used to mark an entry in the auth table as tainted
2018-01-19 06:44:44 +00:00
func ( c * Core ) taintCredEntry ( ctx context . Context , path string ) error {
2017-01-17 18:02:29 +00:00
c . authLock . Lock ( )
defer c . authLock . Unlock ( )
2015-04-03 23:07:45 +00:00
// Taint the entry from the auth table
2015-11-11 16:44:07 +00:00
// We do this on the original since setting the taint operates
// on the entries which a shallow clone shares anyways
2017-03-02 19:37:59 +00:00
entry := c . auth . setTaint ( path , true )
2015-04-03 23:07:45 +00:00
2015-03-19 02:36:17 +00:00
// Ensure there was a match
2017-03-02 19:37:59 +00:00
if entry == nil {
2015-03-19 02:36:17 +00:00
return fmt . Errorf ( "no matching backend" )
}
// Update the auth table
2018-01-19 06:44:44 +00:00
if err := c . persistAuth ( ctx , c . auth , entry . Local ) ; err != nil {
2015-03-19 02:36:17 +00:00
return errors . New ( "failed to update auth table" )
}
2015-11-11 16:44:07 +00:00
2015-03-19 02:36:17 +00:00
return nil
}
2015-03-18 22:46:07 +00:00
// loadCredentials is invoked as part of postUnseal to load the auth table
2018-01-19 06:44:44 +00:00
func ( c * Core ) loadCredentials ( ctx context . Context ) error {
2015-11-11 16:44:07 +00:00
authTable := & MountTable { }
2017-02-17 04:09:39 +00:00
localAuthTable := & MountTable { }
2015-03-18 22:46:07 +00:00
// Load the existing mount table
2018-01-19 06:44:44 +00:00
raw , err := c . barrier . Get ( ctx , coreAuthConfigPath )
2015-03-18 22:46:07 +00:00
if err != nil {
2016-08-19 20:45:17 +00:00
c . logger . Error ( "core: failed to read auth table" , "error" , err )
2015-09-09 19:42:29 +00:00
return errLoadAuthFailed
2015-03-18 22:46:07 +00:00
}
2018-01-19 06:44:44 +00:00
rawLocal , err := c . barrier . Get ( ctx , coreLocalAuthConfigPath )
2017-02-17 04:09:39 +00:00
if err != nil {
c . logger . Error ( "core: failed to read local auth table" , "error" , err )
return errLoadAuthFailed
}
2015-11-11 16:44:07 +00:00
c . authLock . Lock ( )
defer c . authLock . Unlock ( )
2015-03-18 22:46:07 +00:00
if raw != nil {
2016-07-06 16:25:40 +00:00
if err := jsonutil . DecodeJSON ( raw . Value , authTable ) ; err != nil {
2016-08-19 20:45:17 +00:00
c . logger . Error ( "core: failed to decode auth table" , "error" , err )
2015-09-09 19:42:29 +00:00
return errLoadAuthFailed
2015-03-18 22:46:07 +00:00
}
2015-11-11 16:44:07 +00:00
c . auth = authTable
2015-03-18 22:46:07 +00:00
}
2017-11-08 01:30:02 +00:00
var needPersist bool
if c . auth == nil {
c . auth = c . defaultAuthTable ( )
needPersist = true
}
2017-02-17 04:09:39 +00:00
if rawLocal != nil {
if err := jsonutil . DecodeJSON ( rawLocal . Value , localAuthTable ) ; err != nil {
c . logger . Error ( "core: failed to decode local auth table" , "error" , err )
return errLoadAuthFailed
}
2017-11-07 23:04:37 +00:00
if localAuthTable != nil && len ( localAuthTable . Entries ) > 0 {
c . auth . Entries = append ( c . auth . Entries , localAuthTable . Entries ... )
}
2017-02-17 04:09:39 +00:00
}
2015-03-18 22:46:07 +00:00
2017-11-08 01:30:02 +00:00
// Upgrade to typed auth table
if c . auth . Type == "" {
c . auth . Type = credentialTableType
needPersist = true
}
2016-05-26 17:38:51 +00:00
2017-11-08 01:30:02 +00:00
// Upgrade to table-scoped entries
for _ , entry := range c . auth . Entries {
if entry . Table == "" {
entry . Table = c . auth . Type
2016-05-26 17:38:51 +00:00
needPersist = true
}
2017-11-08 01:30:02 +00:00
if entry . Accessor == "" {
accessor , err := c . generateMountAccessor ( "auth_" + 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 17:38:51 +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 17:38:51 +00:00
2017-11-08 01:30:02 +00:00
if ! needPersist {
return nil
2015-03-18 22:46:07 +00:00
}
2018-01-19 06:44:44 +00:00
if err := c . persistAuth ( ctx , c . auth , false ) ; err != nil {
2016-08-19 20:45:17 +00:00
c . logger . Error ( "core: failed to persist auth table" , "error" , err )
2015-09-09 19:42:29 +00:00
return errLoadAuthFailed
2015-03-18 22:46:07 +00:00
}
return nil
}
// persistAuth is used to persist the auth table after modification
2018-01-19 06:44:44 +00:00
func ( c * Core ) persistAuth ( ctx context . Context , table * MountTable , localOnly bool ) error {
2016-05-26 17:38:51 +00:00
if table . Type != credentialTableType {
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" , credentialTableType )
2016-05-26 17:38:51 +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 auth table has wrong table value" , "path" , entry . Path , "entry_table_type" , entry . Table , "actual_type" , table . Type )
2016-05-26 17:38:51 +00:00
return fmt . Errorf ( "invalid auth entry found, not persisting" )
}
}
2017-02-17 04:09:39 +00:00
nonLocalAuth := & MountTable {
Type : credentialTableType ,
}
localAuth := & MountTable {
Type : credentialTableType ,
}
for _ , entry := range table . Entries {
if entry . Local {
localAuth . Entries = append ( localAuth . Entries , entry )
} else {
nonLocalAuth . Entries = append ( nonLocalAuth . Entries , entry )
}
}
2017-03-02 19:37:59 +00:00
if ! localOnly {
// Marshal the table
compressedBytes , err := jsonutil . EncodeJSONAndCompress ( nonLocalAuth , nil )
if err != nil {
c . logger . Error ( "core: failed to encode and/or compress auth table" , "error" , err )
return err
}
2015-03-18 22:46:07 +00:00
2017-03-02 19:37:59 +00:00
// Create an entry
entry := & Entry {
Key : coreAuthConfigPath ,
Value : compressedBytes ,
}
2015-03-18 22:46:07 +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 auth table" , "error" , err )
return err
}
2015-03-18 22:46:07 +00:00
}
2017-02-17 04:09:39 +00:00
// Repeat with local auth
2017-03-02 19:37:59 +00:00
compressedBytes , err := jsonutil . EncodeJSONAndCompress ( localAuth , nil )
2017-02-17 04:09:39 +00:00
if err != nil {
c . logger . Error ( "core: failed to encode and/or compress local auth table" , "error" , err )
return err
}
2017-03-02 19:37:59 +00:00
entry := & Entry {
2017-02-17 04:09:39 +00:00
Key : coreLocalAuthConfigPath ,
Value : compressedBytes ,
}
2018-01-19 06:44:44 +00:00
if err := c . barrier . Put ( ctx , entry ) ; err != nil {
2017-02-17 04:09:39 +00:00
c . logger . Error ( "core: failed to persist local auth table" , "error" , err )
return err
}
2015-03-18 22:46:07 +00:00
return nil
}
// setupCredentials is invoked after we've loaded the auth table to
2015-03-18 22:30:31 +00:00
// initialize the credential backends and setup the router
2018-01-19 06:44:44 +00:00
func ( c * Core ) setupCredentials ( ctx context . Context ) error {
2015-03-18 22:46:07 +00:00
var err error
2016-05-25 21:53:45 +00:00
var persistNeeded bool
2017-10-23 21:15:56 +00:00
var backendType logical . BackendType
2015-11-11 16:44:07 +00:00
c . authLock . Lock ( )
defer c . authLock . Unlock ( )
2015-03-18 22:46:07 +00:00
for _ , entry := range c . auth . Entries {
2017-09-01 05:02:03 +00:00
var backend logical . Backend
2016-05-25 21:53:45 +00:00
// Work around some problematic code that existed in master for a while
if strings . HasPrefix ( entry . Path , credentialRoutePrefix ) {
entry . Path = strings . TrimPrefix ( entry . Path , credentialRoutePrefix )
persistNeeded = true
}
2015-07-01 00:30:43 +00:00
// Create a barrier view using the UUID
2017-02-17 04:09:39 +00:00
viewPath := credentialBarrierPrefix + entry . UUID + "/"
2018-02-09 20:39:27 +00:00
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 )
2018-02-09 20:39:27 +00:00
defer view . setReadOnlyErr ( nil )
2018-02-09 19:04:25 +00:00
2017-10-23 20:49:46 +00:00
// Initialize the backend
2017-02-17 04:09:39 +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
}
2015-07-01 00:30:43 +00:00
2018-01-19 06:44:44 +00:00
backend , err = c . newCredentialBackend ( ctx , entry . Type , sysView , view , conf )
2015-03-18 22:46:07 +00:00
if err != nil {
2016-08-19 20:45:17 +00:00
c . logger . Error ( "core: failed to create credential 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 credential entry" , "path" , entry . Path )
2017-09-01 05:02:03 +00:00
goto ROUTER_MOUNT
}
2015-09-09 19:42:29 +00:00
return errLoadAuthFailed
2015-03-18 22:46:07 +00:00
}
2017-03-04 21:35:41 +00:00
if backend == nil {
return fmt . Errorf ( "nil backend returned from %q factory" , entry . Type )
}
2015-03-18 22:46:07 +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 20:49:46 +00:00
if entry . Type == "plugin" && backendType != logical . TypeCredential {
return fmt . Errorf ( "cannot mount '%s' of type '%s' as an auth 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-09-01 05:02:03 +00:00
ROUTER_MOUNT :
2015-03-18 22:46:07 +00:00
// Mount the backend
2015-04-03 21:24:00 +00:00
path := credentialRoutePrefix + entry . Path
2015-09-04 20:58:12 +00:00
err = c . router . Mount ( backend , path , entry , view )
2015-03-18 22:46:07 +00:00
if err != nil {
2016-08-19 20:45:17 +00:00
c . logger . Error ( "core: failed to mount auth entry" , "path" , entry . Path , "error" , err )
2015-09-09 19:42:29 +00:00
return errLoadAuthFailed
2015-03-18 22:46:07 +00:00
}
2015-03-23 20:41:05 +00:00
2015-04-03 23:07:45 +00:00
// Ensure the path is tainted if set in the mount table
if entry . Tainted {
c . router . Taint ( path )
}
2015-03-23 20:41:05 +00:00
// Check if this is the token store
if entry . Type == "token" {
c . tokenStore = backend . ( * TokenStore )
2015-09-15 16:27:22 +00:00
// this is loaded *after* the normal mounts, including cubbyhole
2017-07-18 16:02:03 +00:00
c . router . tokenStoreSaltFunc = c . tokenStore . Salt
2015-09-15 17:49:53 +00:00
c . tokenStore . cubbyholeBackend = c . router . MatchingBackend ( "cubbyhole/" ) . ( * CubbyholeBackend )
2015-03-23 20:41:05 +00:00
}
2015-03-18 22:46:07 +00:00
}
2016-05-25 21:53:45 +00:00
if persistNeeded {
2018-01-19 06:44:44 +00:00
return c . persistAuth ( ctx , c . auth , false )
2016-05-25 21:53:45 +00:00
}
2015-03-18 22:30:31 +00:00
return nil
}
// teardownCredentials is used before we seal the vault to reset the credential
// backends to their unloaded state. This is reversed by loadCredentials.
2018-01-19 06:44:44 +00:00
func ( c * Core ) teardownCredentials ( ctx context . Context ) error {
2015-11-11 16:44:07 +00:00
c . authLock . Lock ( )
defer c . authLock . Unlock ( )
2016-10-28 19:32:32 +00:00
if c . auth != nil {
authTable := c . auth . shallowClone ( )
for _ , e := range authTable . Entries {
2017-03-04 21:35:41 +00:00
backend := c . router . MatchingBackend ( credentialRoutePrefix + e . Path )
if backend != nil {
2018-01-19 06:44:44 +00:00
backend . Cleanup ( ctx )
2016-10-28 19:32:32 +00:00
}
}
}
2015-03-18 22:46:07 +00:00
c . auth = nil
2015-03-23 20:41:05 +00:00
c . tokenStore = nil
2015-03-18 22:30:31 +00:00
return nil
}
2015-03-18 22:46:07 +00:00
// newCredentialBackend is used to create and configure a new credential backend by name
2015-03-31 01:07:05 +00:00
func ( c * Core ) newCredentialBackend (
2018-01-19 06:44:44 +00:00
ctx context . Context ,
t string ,
sysView logical . SystemView ,
view logical . Storage ,
conf map [ string ] string ) ( logical . Backend , error ) {
2017-04-24 19:15:50 +00:00
if alias , ok := credentialAliases [ t ] ; ok {
t = alias
}
2015-03-18 22:46:07 +00:00
f , ok := c . credentialBackends [ t ]
if ! ok {
return nil , fmt . Errorf ( "unknown backend type: %s" , t )
}
2015-03-31 01:07:05 +00:00
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-07-01 00:30:43 +00:00
if err != nil {
return nil , err
}
2015-09-04 20:58:12 +00:00
2015-07-01 00:30:43 +00:00
return b , nil
2015-03-18 22:46:07 +00:00
}
// defaultAuthTable creates a default auth table
2017-06-26 17:14:36 +00:00
func ( c * Core ) defaultAuthTable ( ) * MountTable {
2016-05-26 17:38:51 +00:00
table := & MountTable {
Type : credentialTableType ,
}
2016-01-13 18:40:08 +00:00
tokenUUID , err := uuid . GenerateUUID ( )
if err != nil {
panic ( fmt . Sprintf ( "could not generate UUID for default auth table token entry: %v" , err ) )
}
2017-06-26 17:14:36 +00:00
tokenAccessor , err := c . generateMountAccessor ( "auth_token" )
if err != nil {
panic ( fmt . Sprintf ( "could not generate accessor for default auth table token entry: %v" , err ) )
}
2015-03-19 16:54:57 +00:00
tokenAuth := & MountEntry {
2016-05-26 17:38:51 +00:00
Table : credentialTableType ,
2015-04-03 21:24:00 +00:00
Path : "token/" ,
2015-03-18 22:46:07 +00:00
Type : "token" ,
Description : "token based credentials" ,
2016-01-13 18:40:08 +00:00
UUID : tokenUUID ,
2017-06-26 17:14:36 +00:00
Accessor : tokenAccessor ,
2015-03-18 22:46:07 +00:00
}
table . Entries = append ( table . Entries , tokenAuth )
return table
}