Update help text and comments

This commit is contained in:
Brian Kassouf 2017-04-11 11:50:34 -07:00
parent c85b7be22f
commit 128f25c13d
9 changed files with 323 additions and 271 deletions

View file

@ -10,7 +10,7 @@ import (
"github.com/hashicorp/vault/helper/pluginutil"
)
// DatabasePluginClient embeds a databasePluginRPCClient and wraps it's close
// DatabasePluginClient embeds a databasePluginRPCClient and wraps it's Close
// method to also call Kill() on the plugin.Client.
type DatabasePluginClient struct {
client *plugin.Client
@ -64,7 +64,7 @@ func newPluginClient(sys pluginutil.Wrapper, pluginRunner *pluginutil.PluginRunn
// ---- RPC client domain ----
// databasePluginRPCClient impliments DatabaseType and is used on the client to
// databasePluginRPCClient implements DatabaseType and is used on the client to
// make RPC calls to a plugin.
type databasePluginRPCClient struct {
client *rpc.Client

View file

@ -9,6 +9,8 @@ import (
// ---- Tracing Middleware Domain ----
// databaseTracingMiddleware wraps a implementation of DatabaseType and executes
// trace logging on function call.
type databaseTracingMiddleware struct {
next DatabaseType
logger log.Logger
@ -77,6 +79,8 @@ func (mw *databaseTracingMiddleware) Close() (err error) {
// ---- Metrics Middleware Domain ----
// databaseMetricsMiddleware wraps an implementation of DatabaseTypes and on
// function call logs metrics about this instance.
type databaseMetricsMiddleware struct {
next DatabaseType

View file

@ -40,11 +40,13 @@ func PluginFactory(pluginName string, sys pluginutil.LookWrapper, logger log.Log
return nil, ErrEmptyPluginName
}
// Look for plugin in the plugin catalog
pluginMeta, err := sys.LookupPlugin(pluginName)
if err != nil {
return nil, err
}
// create a DatabasePluginClient instance
db, err := newPluginClient(sys, pluginMeta)
if err != nil {
return nil, err
@ -76,6 +78,8 @@ var handshakeConfig = plugin.HandshakeConfig{
MagicCookieValue: "926a0820-aea2-be28-51d6-83cdf00e8edb",
}
// DatabasePlugin implements go-plugin's Plugin interface. It has methods for
// retrieving a server and a client instance of the plugin.
type DatabasePlugin struct {
impl DatabaseType
}

View file

@ -8,7 +8,7 @@ import (
)
// NewPluginServer is called from within a plugin and wraps the provided
// DatabaseType implimentation in a databasePluginRPCServer object and starts a
// DatabaseType implementation in a databasePluginRPCServer object and starts a
// RPC server.
func NewPluginServer(db DatabaseType) {
dbPlugin := &DatabasePlugin{
@ -35,7 +35,8 @@ func NewPluginServer(db DatabaseType) {
// ---- RPC server domain ----
// databasePluginRPCServer impliments DatabaseType and is run inside a plugin
// databasePluginRPCServer implements an RPC version of DatabaseType and is run
// inside a plugin. It wraps an underlying implementation of DatabaseType.
type databasePluginRPCServer struct {
impl DatabaseType
}

View file

@ -9,6 +9,7 @@ import (
"github.com/hashicorp/vault/logical/framework"
)
// pathResetConnection configures a path to reset a plugin.
func pathResetConnection(b *databaseBackend) *framework.Path {
return &framework.Path{
Pattern: fmt.Sprintf("reset/%s", framework.GenericNameRegex("name")),
@ -20,15 +21,18 @@ func pathResetConnection(b *databaseBackend) *framework.Path {
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.UpdateOperation: b.pathConnectionReset,
logical.UpdateOperation: b.pathConnectionReset(),
},
HelpSynopsis: pathConfigConnectionHelpSyn,
HelpDescription: pathConfigConnectionHelpDesc,
HelpSynopsis: pathResetConnectionHelpSyn,
HelpDescription: pathResetConnectionHelpDesc,
}
}
func (b *databaseBackend) pathConnectionReset(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
// pathConnectionReset resets a plugin by closing the existing instance and
// creating a new one.
func (b *databaseBackend) pathConnectionReset() framework.OperationFunc {
return func(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
name := data.Get("name").(string)
if name == "" {
return logical.ErrorResponse("Empty name attribute given"), nil
@ -46,6 +50,7 @@ func (b *databaseBackend) pathConnectionReset(req *logical.Request, data *framew
}
return nil, nil
}
}
// pathConfigurePluginConnection returns a configured framework.Path setup to
@ -62,13 +67,15 @@ func pathConfigurePluginConnection(b *databaseBackend) *framework.Path {
"verify_connection": &framework.FieldSchema{
Type: framework.TypeBool,
Default: true,
Description: `If set, connection_url is verified by actually connecting to the database`,
Description: `If set, the connection details are verified by
actually connecting to the database`,
},
"plugin_name": &framework.FieldSchema{
Type: framework.TypeString,
Description: `Maximum amount of time a connection may be reused;
a zero or negative value reuses connections forever.`,
Description: `The name of a builtin or previously registered
plugin known to vault. This endpoint will create an instance of
that plugin type.`,
},
},
@ -198,16 +205,32 @@ func (b *databaseBackend) connectionWriteHandler() framework.OperationFunc {
}
const pathConfigConnectionHelpSyn = `
Configure the connection string to talk to PostgreSQL.
Configure connection details to a database plugin.
`
const pathConfigConnectionHelpDesc = `
This path configures the connection string used to connect to PostgreSQL.
The value of the string can be a URL, or a PG style string in the
format of "user=foo host=bar" etc.
This path configures the connection details used to connect to a particular
database. This path runs the provided plugin name and passes the configured
connection details to the plugin. See the documentation for the plugin specified
for a full list of accepted connection details.
The URL looks like:
"postgresql://user:pass@host:port/dbname"
In addition to the database specific connection details, this endpoing also
accepts:
When configuring the connection string, the backend will verify its validity.
* "plugin_name" (required) - The name of a builtin or previously registered
plugin known to vault. This endpoint will create an instance of that
plugin type.
* "verify_connection" - A boolean value denoting if the plugin should verify
it is able to connect to the database using the provided connection
details.
`
const pathResetConnectionHelpSyn = `
Resets a database plugin.
`
const pathResetConnectionHelpDesc = `
This path resets the database connection by closing the existing database plugin
instance and running a new one.
`

View file

@ -19,7 +19,7 @@ func pathRoleCreate(b *databaseBackend) *framework.Path {
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ReadOperation: b.pathRoleCreateRead,
logical.ReadOperation: b.pathRoleCreateRead(),
},
HelpSynopsis: pathRoleCreateReadHelpSyn,
@ -27,7 +27,8 @@ func pathRoleCreate(b *databaseBackend) *framework.Path {
}
}
func (b *databaseBackend) pathRoleCreateRead(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
func (b *databaseBackend) pathRoleCreateRead() framework.OperationFunc {
return func(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
name := data.Get("name").(string)
// Get the role
@ -66,6 +67,7 @@ func (b *databaseBackend) pathRoleCreateRead(req *logical.Request, data *framewo
})
resp.Secret.TTL = role.DefaultTTL
return resp, nil
}
}
const pathRoleCreateReadHelpSyn = `

View file

@ -14,7 +14,7 @@ func pathListRoles(b *databaseBackend) *framework.Path {
Pattern: "roles/?$",
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ListOperation: b.pathRoleList,
logical.ListOperation: b.pathRoleList(),
},
HelpSynopsis: pathRoleHelpSyn,
@ -35,12 +35,13 @@ func pathRoles(b *databaseBackend) *framework.Path {
Type: framework.TypeString,
Description: "Name of the database this role acts on.",
},
"creation_statements": {
Type: framework.TypeString,
Description: "SQL string to create a user. See help for more info.",
Description: `Statements to be executed to create a user. Must be a semicolon-separated
string, a base64-encoded semicolon-separated string, a serialized JSON string
array, or a base64-encoded serialized JSON string array. The '{{name}}',
'{{password}}', and '{{expiration}}' values will be substituted.`,
},
"revocation_statements": {
Type: framework.TypeString,
Description: `Statements to be executed to revoke a user. Must be a semicolon-separated
@ -75,9 +76,9 @@ func pathRoles(b *databaseBackend) *framework.Path {
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ReadOperation: b.pathRoleRead,
logical.UpdateOperation: b.pathRoleCreate,
logical.DeleteOperation: b.pathRoleDelete,
logical.ReadOperation: b.pathRoleRead(),
logical.UpdateOperation: b.pathRoleCreate(),
logical.DeleteOperation: b.pathRoleDelete(),
},
HelpSynopsis: pathRoleHelpSyn,
@ -85,16 +86,19 @@ func pathRoles(b *databaseBackend) *framework.Path {
}
}
func (b *databaseBackend) pathRoleDelete(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
func (b *databaseBackend) pathRoleDelete() framework.OperationFunc {
return func(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
err := req.Storage.Delete("role/" + data.Get("name").(string))
if err != nil {
return nil, err
}
return nil, nil
}
}
func (b *databaseBackend) pathRoleRead(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
func (b *databaseBackend) pathRoleRead() framework.OperationFunc {
return func(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
role, err := b.Role(req.Storage, data.Get("name").(string))
if err != nil {
return nil, err
@ -113,18 +117,22 @@ func (b *databaseBackend) pathRoleRead(req *logical.Request, data *framework.Fie
"max_ttl": role.MaxTTL.String(),
},
}, nil
}
}
func (b *databaseBackend) pathRoleList(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
func (b *databaseBackend) pathRoleList() framework.OperationFunc {
return func(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
entries, err := req.Storage.List("role/")
if err != nil {
return nil, err
}
return logical.ListResponse(entries), nil
}
}
func (b *databaseBackend) pathRoleCreate(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
func (b *databaseBackend) pathRoleCreate() framework.OperationFunc {
return func(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
name := data.Get("name").(string)
if name == "" {
return logical.ErrorResponse("Empty role name attribute given"), nil
@ -163,8 +171,6 @@ func (b *databaseBackend) pathRoleCreate(req *logical.Request, data *framework.F
RenewStatements: renewStmts,
}
// TODO: Think about preparing the statments to test.
// Store it
entry, err := logical.StorageEntryJSON("role/"+name, &roleEntry{
DBName: dbName,
@ -180,6 +186,7 @@ func (b *databaseBackend) pathRoleCreate(req *logical.Request, data *framework.F
}
return nil, nil
}
}
type roleEntry struct {
@ -196,10 +203,14 @@ Manage the roles that can be created with this backend.
const pathRoleHelpDesc = `
This path lets you manage the roles that can be created with this backend.
The "sql" parameter customizes the SQL string used to create the role.
This can be a sequence of SQL queries. Some substitution will be done to the
SQL string for certain keys. The names of the variables must be surrounded
by "{{" and "}}" to be replaced.
The "db_name" parameter is required and configures the name of the database
connection to use.
The "creation_statements" parameter customizes the string used to create the
credentials. This can be a sequence of SQL queries, or other statement formats
for a particular database type. Some substitution will be done to the statement
strings for certain keys. The names of the variables must be surrounded by "{{"
and "}}" to be replaced.
* "name" - The random username generated for the DB user.
@ -207,7 +218,7 @@ by "{{" and "}}" to be replaced.
* "expiration" - The timestamp when this user will expire.
Example of a decent SQL query to use:
Example of a decent creation_statements for a postgresql database plugin:
CREATE ROLE "{{name}}" WITH
LOGIN
@ -215,14 +226,17 @@ Example of a decent SQL query to use:
VALID UNTIL '{{expiration}}';
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "{{name}}";
Note the above user would be able to access everything in schema public.
For more complex GRANT clauses, see the PostgreSQL manual.
The "revocation_sql" parameter customizes the SQL string used to revoke a user.
Example of a decent revocation SQL query to use:
The "revocation_statements" parameter customizes the statement string used to
revoke a user. Example of a decent revocation_statements for a postgresql
database plugin:
REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM {{name}};
REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM {{name}};
REVOKE USAGE ON SCHEMA public FROM {{name}};
DROP ROLE IF EXISTS {{name}};
The "renew_statements" parameter customizes the statement string used to renew a
user.
The "rollback_statements' parameter customizes the statement string used to
rollback a change if needed.
`

View file

@ -14,12 +14,13 @@ func secretCreds(b *databaseBackend) *framework.Secret {
Type: SecretCredsType,
Fields: map[string]*framework.FieldSchema{},
Renew: b.secretCredsRenew,
Revoke: b.secretCredsRevoke,
Renew: b.secretCredsRenew(),
Revoke: b.secretCredsRevoke(),
}
}
func (b *databaseBackend) secretCredsRenew(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
func (b *databaseBackend) secretCredsRenew() framework.OperationFunc {
return func(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
// Get the username from the internal data
usernameRaw, ok := req.Secret.InternalData["username"]
if !ok {
@ -41,7 +42,7 @@ func (b *databaseBackend) secretCredsRenew(req *logical.Request, d *framework.Fi
}
f := framework.LeaseExtend(role.DefaultTTL, role.MaxTTL, b.System())
resp, err := f(req, d)
resp, err := f(req, data)
if err != nil {
return nil, err
}
@ -65,9 +66,11 @@ func (b *databaseBackend) secretCredsRenew(req *logical.Request, d *framework.Fi
}
return resp, nil
}
}
func (b *databaseBackend) secretCredsRevoke(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
func (b *databaseBackend) secretCredsRevoke() framework.OperationFunc {
return func(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
// Get the username from the internal data
usernameRaw, ok := req.Secret.InternalData["username"]
if !ok {
@ -122,4 +125,5 @@ func (b *databaseBackend) secretCredsRevoke(req *logical.Request, d *framework.F
}
return resp, nil
}
}

View file

@ -88,11 +88,11 @@ func (d StaticSystemView) ReplicationState() consts.ReplicationState {
}
func (d StaticSystemView) ResponseWrapData(data map[string]interface{}, ttl time.Duration, jwt bool) (string, error) {
return "", errors.New("ResponseWrapData is not implimented in StaticSystemView")
return "", errors.New("ResponseWrapData is not implemented in StaticSystemView")
}
func (d StaticSystemView) LookupPlugin(name string) (*pluginutil.PluginRunner, error) {
return nil, errors.New("LookupPlugin is not implimented in StaticSystemView")
return nil, errors.New("LookupPlugin is not implemented in StaticSystemView")
}
func (d StaticSystemView) MlockDisabled() bool {