Update the builtin keys; move catalog to core; protect against unset plugin directory

This commit is contained in:
Brian Kassouf 2017-04-24 10:30:33 -07:00
parent 3ceb7b69e1
commit f4ef3df4bd
7 changed files with 47 additions and 62 deletions

View File

@ -8,7 +8,6 @@ import (
"net/url" "net/url"
"os" "os"
"os/signal" "os/signal"
"path/filepath"
"runtime" "runtime"
"sort" "sort"
"strconv" "strconv"
@ -21,7 +20,6 @@ import (
colorable "github.com/mattn/go-colorable" colorable "github.com/mattn/go-colorable"
log "github.com/mgutz/logxi/v1" log "github.com/mgutz/logxi/v1"
homedir "github.com/mitchellh/go-homedir"
"google.golang.org/grpc/grpclog" "google.golang.org/grpc/grpclog"
@ -245,23 +243,6 @@ func (c *ServerCommand) Run(args []string) int {
coreConfig.DevToken = devRootTokenID coreConfig.DevToken = devRootTokenID
} }
if config.PluginDirectory == "" {
homePath, err := homedir.Dir()
if err != nil {
c.Ui.Output(fmt.Sprintf(
"Error getting user's home directory: %v", err))
return 1
}
coreConfig.PluginDirectory = filepath.Join(homePath, "/.vault-plugins/")
err = os.Mkdir(coreConfig.PluginDirectory, 0700)
if err != nil && !os.IsExist(err) {
c.Ui.Output(fmt.Sprintf(
"Error making default plugin directory: %v", err))
return 1
}
}
var disableClustering bool var disableClustering bool
// Initialize the separate HA storage backend, if it exists // Initialize the separate HA storage backend, if it exists

View File

@ -7,29 +7,21 @@ import (
type BuiltinFactory func() (interface{}, error) type BuiltinFactory func() (interface{}, error)
var BuiltinPlugins *builtinPlugins = &builtinPlugins{ var plugins map[string]BuiltinFactory = map[string]BuiltinFactory{
plugins: map[string]BuiltinFactory{ "mysql-database-plugin": mysql.New,
"mysql-database-plugin": mysql.New, "postgresql-database-plugin": postgresql.New,
"postgresql-database-plugin": postgresql.New,
},
} }
// The list of builtin plugins should not be changed by any other package, so we func Get(name string) (BuiltinFactory, bool) {
// store them in an unexported variable in this unexported struct. f, ok := plugins[name]
type builtinPlugins struct {
plugins map[string]BuiltinFactory
}
func (b *builtinPlugins) Get(name string) (BuiltinFactory, bool) {
f, ok := b.plugins[name]
return f, ok return f, ok
} }
func (b *builtinPlugins) Keys() []string { func Keys() []string {
keys := make([]string, len(b.plugins)) keys := make([]string, len(plugins))
i := 0 i := 0
for k := range b.plugins { for k := range plugins {
keys[i] = k keys[i] = k
i++ i++
} }

View File

@ -12,8 +12,8 @@ import (
) )
var ( var (
// PluginUnwrapTokenEnv is the ENV name used to pass unwrap tokens to the // PluginUnwrapTokenEnv is the ENV name used to pass the configuration for
// plugin. // enabling mlock
PluginMlockEnabled = "VAULT_PLUGIN_MLOCK_ENABLED" PluginMlockEnabled = "VAULT_PLUGIN_MLOCK_ENABLED"
) )

View File

@ -710,13 +710,19 @@ func NewSystemBackend(core *Core, config *logical.BackendConfig) (logical.Backen
Fields: map[string]*framework.FieldSchema{ Fields: map[string]*framework.FieldSchema{
"name": &framework.FieldSchema{ "name": &framework.FieldSchema{
Type: framework.TypeString, Type: framework.TypeString,
Description: "The name of the plugin",
}, },
"sha_256": &framework.FieldSchema{ "sha_256": &framework.FieldSchema{
Type: framework.TypeString, Type: framework.TypeString,
Description: `The SHA256 sum of the executable used in the
command field. This should be HEX encoded.`,
}, },
"command": &framework.FieldSchema{ "command": &framework.FieldSchema{
Type: framework.TypeString, Type: framework.TypeString,
Description: `The command used to start the plugin. The
executable defined in this command must exist in vault's
plugin directory.`,
}, },
}, },
@ -767,8 +773,7 @@ func (b *SystemBackend) handlePluginCatalogList(req *logical.Request, d *framewo
return nil, err return nil, err
} }
resp := logical.ListResponse(plugins) return logical.ListResponse(plugins), nil
return resp, nil
} }
func (b *SystemBackend) handlePluginCatalogUpdate(req *logical.Request, d *framework.FieldData) (*logical.Response, error) { func (b *SystemBackend) handlePluginCatalogUpdate(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
@ -2524,7 +2529,7 @@ This path responds to the following HTTP methods.
`Configures the plugins known to vault`, `Configures the plugins known to vault`,
` `
This path responds to the following HTTP methods. This path responds to the following HTTP methods.
GET / LIST /
Returns a list of names of configured plugins. Returns a list of names of configured plugins.
GET /<name> GET /<name>

View File

@ -1129,8 +1129,8 @@ func TestSystemBackend_PluginCatalog_CRUD(t *testing.T) {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
if len(resp.Data["keys"].([]string)) != len(builtinplugins.BuiltinPlugins.Keys()) { if len(resp.Data["keys"].([]string)) != len(builtinplugins.Keys()) {
t.Fatalf("Wrong number of plugins, got %d, expected %d", len(resp.Data["keys"].([]string)), len(builtinplugins.BuiltinPlugins.Keys())) t.Fatalf("Wrong number of plugins, got %d, expected %d", len(resp.Data["keys"].([]string)), len(builtinplugins.Keys()))
} }
req = logical.TestRequest(t, logical.ReadOperation, "plugin-catalog/mysql-database-plugin") req = logical.TestRequest(t, logical.ReadOperation, "plugin-catalog/mysql-database-plugin")
@ -1143,7 +1143,7 @@ func TestSystemBackend_PluginCatalog_CRUD(t *testing.T) {
Name: "mysql-database-plugin", Name: "mysql-database-plugin",
Builtin: true, Builtin: true,
} }
expectedBuiltin.BuiltinFactory, _ = builtinplugins.BuiltinPlugins.Get("mysql-database-plugin") expectedBuiltin.BuiltinFactory, _ = builtinplugins.Get("mysql-database-plugin")
p := resp.Data["plugin"].(*pluginutil.PluginRunner) p := resp.Data["plugin"].(*pluginutil.PluginRunner)
if &(p.BuiltinFactory) == &(expectedBuiltin.BuiltinFactory) { if &(p.BuiltinFactory) == &(expectedBuiltin.BuiltinFactory) {

View File

@ -16,7 +16,8 @@ import (
) )
var ( var (
pluginCatalogPrefix = "plugin-catalog/" pluginCatalogPath = "core/plugin-catalog/"
ErrDirectoryNotConfigured = errors.New("could not set plugin, plugin directory is not configured")
) )
// PluginCatalog keeps a record of plugins known to vault. External plugins need // PluginCatalog keeps a record of plugins known to vault. External plugins need
@ -31,7 +32,7 @@ type PluginCatalog struct {
func (c *Core) setupPluginCatalog() error { func (c *Core) setupPluginCatalog() error {
c.pluginCatalog = &PluginCatalog{ c.pluginCatalog = &PluginCatalog{
catalogView: c.systemBarrierView.SubView(pluginCatalogPrefix), catalogView: NewBarrierView(c.barrier, pluginCatalogPath),
directory: c.pluginDirectory, directory: c.pluginDirectory,
} }
@ -45,22 +46,24 @@ func (c *PluginCatalog) Get(name string) (*pluginutil.PluginRunner, error) {
c.lock.RLock() c.lock.RLock()
defer c.lock.RUnlock() defer c.lock.RUnlock()
// Look for external plugins in the barrier // If the directory isn't set only look for builtin plugins.
out, err := c.catalogView.Get(name) if c.directory != "" {
if err != nil { // Look for external plugins in the barrier
return nil, fmt.Errorf("failed to retrieve plugin \"%s\": %v", name, err) out, err := c.catalogView.Get(name)
} if err != nil {
if out != nil { return nil, fmt.Errorf("failed to retrieve plugin \"%s\": %v", name, err)
entry := new(pluginutil.PluginRunner)
if err := jsonutil.DecodeJSON(out.Value, entry); err != nil {
return nil, fmt.Errorf("failed to decode plugin entry: %v", err)
} }
if out != nil {
entry := new(pluginutil.PluginRunner)
if err := jsonutil.DecodeJSON(out.Value, entry); err != nil {
return nil, fmt.Errorf("failed to decode plugin entry: %v", err)
}
return entry, nil return entry, nil
}
} }
// Look for builtin plugins // Look for builtin plugins
if factory, ok := builtinplugins.BuiltinPlugins.Get(name); ok { if factory, ok := builtinplugins.Get(name); ok {
return &pluginutil.PluginRunner{ return &pluginutil.PluginRunner{
Name: name, Name: name,
Builtin: true, Builtin: true,
@ -74,6 +77,10 @@ func (c *PluginCatalog) Get(name string) (*pluginutil.PluginRunner, error) {
// Set registers a new external plugin with the catalog, or updates an existing // Set registers a new external plugin with the catalog, or updates an existing
// external plugin. It takes the name, command and SHA256 of the plugin. // external plugin. It takes the name, command and SHA256 of the plugin.
func (c *PluginCatalog) Set(name, command string, sha256 []byte) error { func (c *PluginCatalog) Set(name, command string, sha256 []byte) error {
if c.directory == "" {
return ErrDirectoryNotConfigured
}
c.lock.Lock() c.lock.Lock()
defer c.lock.Unlock() defer c.lock.Unlock()
@ -143,7 +150,7 @@ func (c *PluginCatalog) List() ([]string, error) {
} }
// Get the keys for builtin plugins // Get the keys for builtin plugins
builtinKeys := builtinplugins.BuiltinPlugins.Keys() builtinKeys := builtinplugins.Keys()
// Use a map to unique the two lists // Use a map to unique the two lists
mapKeys := make(map[string]bool) mapKeys := make(map[string]bool)

View File

@ -32,7 +32,7 @@ func TestPluginCatalog_CRUD(t *testing.T) {
Name: "mysql-database-plugin", Name: "mysql-database-plugin",
Builtin: true, Builtin: true,
} }
expectedBuiltin.BuiltinFactory, _ = builtinplugins.BuiltinPlugins.Get("mysql-database-plugin") expectedBuiltin.BuiltinFactory, _ = builtinplugins.Get("mysql-database-plugin")
if &(p.BuiltinFactory) == &(expectedBuiltin.BuiltinFactory) { if &(p.BuiltinFactory) == &(expectedBuiltin.BuiltinFactory) {
t.Fatal("expected BuiltinFactory did not match actual") t.Fatal("expected BuiltinFactory did not match actual")
@ -90,7 +90,7 @@ func TestPluginCatalog_CRUD(t *testing.T) {
Name: "mysql-database-plugin", Name: "mysql-database-plugin",
Builtin: true, Builtin: true,
} }
expectedBuiltin.BuiltinFactory, _ = builtinplugins.BuiltinPlugins.Get("mysql-database-plugin") expectedBuiltin.BuiltinFactory, _ = builtinplugins.Get("mysql-database-plugin")
if &(p.BuiltinFactory) == &(expectedBuiltin.BuiltinFactory) { if &(p.BuiltinFactory) == &(expectedBuiltin.BuiltinFactory) {
t.Fatal("expected BuiltinFactory did not match actual") t.Fatal("expected BuiltinFactory did not match actual")
@ -113,7 +113,7 @@ func TestPluginCatalog_List(t *testing.T) {
core.pluginCatalog.directory = sym core.pluginCatalog.directory = sym
// Get builtin plugins and sort them // Get builtin plugins and sort them
builtinKeys := builtinplugins.BuiltinPlugins.Keys() builtinKeys := builtinplugins.Keys()
sort.Strings(builtinKeys) sort.Strings(builtinKeys)
// List only builtin plugins // List only builtin plugins