Calls to builtin plugins now go directly to the implementation instead of go-plugin

This commit is contained in:
Brian Kassouf
2017-04-20 18:46:41 -07:00
parent d9ce189b33
commit f1fa617e03
13 changed files with 94 additions and 179 deletions

View File

@@ -11,10 +11,10 @@ import (
"testing"
"github.com/hashicorp/vault/builtin/logical/database/dbplugin"
"github.com/hashicorp/vault/helper/builtinplugins"
"github.com/hashicorp/vault/helper/pluginutil"
"github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/plugins/database/postgresql"
"github.com/hashicorp/vault/vault"
"github.com/lib/pq"
"github.com/mitchellh/mapstructure"
@@ -91,8 +91,7 @@ func TestBackend_PluginMain(t *testing.T) {
return
}
f, _ := builtinplugins.BuiltinPlugins.Get("postgresql-database-plugin")
f()
postgresql.Run()
}
func TestBackend_config_connection(t *testing.T) {

View File

@@ -33,16 +33,33 @@ type Statements struct {
// object in a logging and metrics middleware.
func PluginFactory(pluginName string, sys pluginutil.LookWrapper, logger log.Logger) (DatabaseType, error) {
// Look for plugin in the plugin catalog
pluginMeta, err := sys.LookupPlugin(pluginName)
pluginRunner, err := sys.LookupPlugin(pluginName)
if err != nil {
return nil, err
}
var db DatabaseType
if pluginRunner.Builtin {
// Plugin is builtin so we can retrieve an instance of the interface
// from the pluginRunner. Then cast it to a DatabaseType.
dbRaw, err := pluginRunner.BuiltinFactory()
if err != nil {
return nil, fmt.Errorf("error getting plugin type: %s", err)
}
var ok bool
db, ok = dbRaw.(DatabaseType)
if !ok {
return nil, fmt.Errorf("unsuported database type: %s", pluginName)
}
} else {
// create a DatabasePluginClient instance
db, err := newPluginClient(sys, pluginMeta)
db, err = newPluginClient(sys, pluginRunner)
if err != nil {
return nil, err
}
}
typeStr, err := db.Type()
if err != nil {

View File

@@ -331,11 +331,5 @@ func Commands(metaPtr *meta.Meta) map[string]cli.CommandFactory {
Ui: metaPtr.Ui,
}, nil
},
"plugin-exec": func() (cli.Command, error) {
return &command.PluginExec{
Meta: *metaPtr,
}, nil
},
}
}

View File

@@ -1,66 +0,0 @@
package command
import (
"fmt"
"strings"
"github.com/hashicorp/vault/helper/builtinplugins"
"github.com/hashicorp/vault/meta"
)
type PluginExec struct {
meta.Meta
}
func (c *PluginExec) Run(args []string) int {
flags := c.Meta.FlagSet("plugin-exec", meta.FlagSetDefault)
flags.Usage = func() { c.Ui.Error(c.Help()) }
if err := flags.Parse(args); err != nil {
return 1
}
args = flags.Args()
if len(args) != 1 {
flags.Usage()
c.Ui.Error(fmt.Sprintf(
"\nplugin-exec expects one argument: the plugin to execute."))
return 1
}
pluginName := args[0]
runner, ok := builtinplugins.BuiltinPlugins.Get(pluginName)
if !ok {
c.Ui.Error(fmt.Sprintf(
"No plugin with the name %s found", pluginName))
return 1
}
err := runner()
if err != nil {
c.Ui.Error(fmt.Sprintf(
"Error running plugin: %s", err))
return 1
}
return 0
}
func (c *PluginExec) Synopsis() string {
return "Runs a builtin plugin. Should only be called by vault."
}
func (c *PluginExec) Help() string {
helpText := `
Usage: vault plugin-exec type
Runs a builtin plugin. Should only be called by vault.
This will execute a plugin for use in a plugable location in vault. If run by
a cli user it will print a message indicating it can not be executed by anyone
other than vault. For supported plugin types see the vault documentation.
General Options:
` + meta.GeneralOptionsUsage()
return strings.TrimSpace(helpText)
}

View File

@@ -1,10 +1,8 @@
package command
import (
"crypto/sha256"
"encoding/base64"
"fmt"
"io"
"net"
"net/http"
"net/url"
@@ -133,33 +131,6 @@ func (c *ServerCommand) Run(args []string) int {
dev = true
}
// Record the vault binary's location and SHA-256 checksum for use in
// builtin plugins.
ex, err := os.Executable()
if err != nil {
c.Ui.Output(fmt.Sprintf(
"Error looking up vault binary: %s", err))
return 1
}
file, err := os.Open(ex)
if err != nil {
c.Ui.Output(fmt.Sprintf(
"Error loading vault binary: %s", err))
return 1
}
defer file.Close()
hash := sha256.New()
_, err = io.Copy(hash, file)
if err != nil {
c.Ui.Output(fmt.Sprintf(
"Error checksumming vault binary: %s", err))
return 1
}
sha256Value := hash.Sum(nil)
// Validation
if !dev {
switch {
@@ -269,8 +240,6 @@ func (c *ServerCommand) Run(args []string) int {
ClusterName: config.ClusterName,
CacheSize: config.CacheSize,
PluginDirectory: config.PluginDirectory,
VaultBinaryLocation: ex,
VaultBinarySHA256: sha256Value,
}
if dev {
coreConfig.DevToken = devRootTokenID

View File

@@ -5,20 +5,22 @@ import (
"github.com/hashicorp/vault/plugins/database/postgresql"
)
type BuiltinFactory func() (interface{}, error)
var BuiltinPlugins *builtinPlugins = &builtinPlugins{
plugins: map[string]func() error{
"mysql-database-plugin": mysql.Run,
"postgresql-database-plugin": postgresql.Run,
plugins: map[string]BuiltinFactory{
"mysql-database-plugin": mysql.New,
"postgresql-database-plugin": postgresql.New,
},
}
// The list of builtin plugins should not be changed by any other package, so we
// store them in an unexported variable in this unexported struct.
type builtinPlugins struct {
plugins map[string]func() error
plugins map[string]BuiltinFactory
}
func (b *builtinPlugins) Get(name string) (func() error, bool) {
func (b *builtinPlugins) Get(name string) (BuiltinFactory, bool) {
f, ok := b.plugins[name]
return f, ok
}

View File

@@ -45,6 +45,7 @@ type PluginRunner struct {
Args []string `json:"args"`
Sha256 []byte `json:"sha256"`
Builtin bool `json:"builtin"`
BuiltinFactory func() (interface{}, error) `json:"-"`
}
// Run takes a wrapper instance, and the go-plugin paramaters and executes a

View File

@@ -23,7 +23,7 @@ type MySQL struct {
credsutil.CredentialsProducer
}
func New() *MySQL {
func New() (interface{}, error) {
connProducer := &connutil.SQLConnectionProducer{}
connProducer.Type = mySQLTypeName
@@ -37,14 +37,17 @@ func New() *MySQL {
CredentialsProducer: credsProducer,
}
return dbType
return dbType, nil
}
// Run instantiates a MySQL object, and runs the RPC server for the plugin
func Run() error {
dbType := New()
dbType, err := New()
if err != nil {
return err
}
dbplugin.NewPluginServer(dbType)
dbplugin.NewPluginServer(dbType.(*MySQL))
return nil
}

View File

@@ -66,7 +66,8 @@ func TestMySQL_Initialize(t *testing.T) {
"connection_url": connURL,
}
db := New()
dbRaw, _ := New()
db := dbRaw.(*MySQL)
connProducer := db.ConnectionProducer.(*connutil.SQLConnectionProducer)
err := db.Initialize(connectionDetails, true)
@@ -92,7 +93,8 @@ func TestMySQL_CreateUser(t *testing.T) {
"connection_url": connURL,
}
db := New()
dbRaw, _ := New()
db := dbRaw.(*MySQL)
err := db.Initialize(connectionDetails, true)
if err != nil {
@@ -127,7 +129,8 @@ func TestMySQL_RevokeUser(t *testing.T) {
"connection_url": connURL,
}
db := New()
dbRaw, _ := New()
db := dbRaw.(*MySQL)
err := db.Initialize(connectionDetails, true)
if err != nil {

View File

@@ -16,7 +16,8 @@ import (
const postgreSQLTypeName string = "postgres"
func New() *PostgreSQL {
// New implements builtinplugins.BuiltinFactory
func New() (interface{}, error) {
connProducer := &connutil.SQLConnectionProducer{}
connProducer.Type = postgreSQLTypeName
@@ -30,14 +31,17 @@ func New() *PostgreSQL {
CredentialsProducer: credsProducer,
}
return dbType
return dbType, nil
}
// Run instatiates a PostgreSQL object, and runs the RPC server for the plugin
func Run() error {
dbType := New()
dbType, err := New()
if err != nil {
return err
}
dbplugin.NewPluginServer(dbType)
dbplugin.NewPluginServer(dbType.(*PostgreSQL))
return nil
}

View File

@@ -66,7 +66,9 @@ func TestPostgreSQL_Initialize(t *testing.T) {
"connection_url": connURL,
}
db := New()
dbRaw, _ := New()
db := dbRaw.(*PostgreSQL)
connProducer := db.ConnectionProducer.(*connutil.SQLConnectionProducer)
err := db.Initialize(connectionDetails, true)
@@ -92,7 +94,8 @@ func TestPostgreSQL_CreateUser(t *testing.T) {
"connection_url": connURL,
}
db := New()
dbRaw, _ := New()
db := dbRaw.(*PostgreSQL)
err := db.Initialize(connectionDetails, true)
if err != nil {
t.Fatalf("err: %s", err)
@@ -136,7 +139,8 @@ func TestPostgreSQL_RenewUser(t *testing.T) {
"connection_url": connURL,
}
db := New()
dbRaw, _ := New()
db := dbRaw.(*PostgreSQL)
err := db.Initialize(connectionDetails, true)
if err != nil {
t.Fatalf("err: %s", err)
@@ -176,7 +180,8 @@ func TestPostgreSQL_RevokeUser(t *testing.T) {
"connection_url": connURL,
}
db := New()
dbRaw, _ := New()
db := dbRaw.(*PostgreSQL)
err := db.Initialize(connectionDetails, true)
if err != nil {
t.Fatalf("err: %s", err)

View File

@@ -335,12 +335,6 @@ type Core struct {
// pluginDirectory is the location vault will look for plugin binaries
pluginDirectory string
// vaultBinaryLocation is used to run builtin plugins in secure mode
vaultBinaryLocation string
// vaultBinarySHA256 is used to run builtin plugins in secure mode
vaultBinarySHA256 []byte
// pluginCatalog is used to manage plugin configurations
pluginCatalog *PluginCatalog
@@ -390,8 +384,6 @@ type CoreConfig struct {
EnableUI bool `json:"ui" structs:"ui" mapstructure:"ui"`
PluginDirectory string `json:"plugin_directory" structs:"plugin_directory" mapstructure:"plugin_directory"`
VaultBinaryLocation string `json:"vault_binary_location" structs:"vault_binary_location" mapstructure:"vault_binary_location"`
VaultBinarySHA256 []byte `json:"vault_binary_sha256" structs:"vault_binary_sha256" mapstructure:"vault_binary_sha256"`
ReloadFuncs *map[string][]ReloadFunc
ReloadFuncsLock *sync.RWMutex
@@ -449,8 +441,6 @@ func NewCore(conf *CoreConfig) (*Core, error) {
clusterName: conf.ClusterName,
clusterListenerShutdownCh: make(chan struct{}),
clusterListenerShutdownSuccessCh: make(chan struct{}),
vaultBinaryLocation: conf.VaultBinaryLocation,
vaultBinarySHA256: conf.VaultBinarySHA256,
disableMlock: conf.DisableMlock,
}

View File

@@ -25,8 +25,6 @@ var (
type PluginCatalog struct {
catalogView *BarrierView
directory string
vaultCommand string
vaultSHA256 []byte
lock sync.RWMutex
}
@@ -35,8 +33,6 @@ func (c *Core) setupPluginCatalog() error {
c.pluginCatalog = &PluginCatalog{
catalogView: c.systemBarrierView.SubView(pluginCatalogPrefix),
directory: c.pluginDirectory,
vaultCommand: c.vaultBinaryLocation,
vaultSHA256: c.vaultBinarySHA256,
}
return nil
@@ -64,17 +60,15 @@ func (c *PluginCatalog) Get(name string) (*pluginutil.PluginRunner, error) {
}
// Look for builtin plugins
if _, ok := builtinplugins.BuiltinPlugins.Get(name); !ok {
return nil, fmt.Errorf("no plugin found with name: %s", name)
}
if factory, ok := builtinplugins.BuiltinPlugins.Get(name); ok {
return &pluginutil.PluginRunner{
Name: name,
Command: c.vaultCommand,
Args: []string{"plugin-exec", name},
Sha256: c.vaultSHA256,
Builtin: true,
BuiltinFactory: factory,
}, nil
}
return nil, fmt.Errorf("no plugin found with name: %s", name)
}
// Set registers a new external plugin with the catalog, or updates an existing