2016-12-19 18:15:58 +00:00
|
|
|
package database
|
|
|
|
|
|
|
|
import (
|
2017-12-14 22:03:11 +00:00
|
|
|
"context"
|
2017-04-13 00:35:02 +00:00
|
|
|
"errors"
|
2016-12-19 18:15:58 +00:00
|
|
|
"fmt"
|
2018-04-07 15:06:04 +00:00
|
|
|
"net/url"
|
|
|
|
"strings"
|
2016-12-19 18:15:58 +00:00
|
|
|
|
|
|
|
"github.com/fatih/structs"
|
2019-11-11 17:04:24 +00:00
|
|
|
"github.com/hashicorp/errwrap"
|
2018-03-21 19:05:56 +00:00
|
|
|
uuid "github.com/hashicorp/go-uuid"
|
2020-10-15 19:20:12 +00:00
|
|
|
v5 "github.com/hashicorp/vault/sdk/database/dbplugin/v5"
|
2019-04-12 21:54:35 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/framework"
|
2019-04-13 07:44:06 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/logical"
|
2016-12-19 18:15:58 +00:00
|
|
|
)
|
|
|
|
|
2017-04-13 00:35:02 +00:00
|
|
|
var (
|
2017-05-01 22:30:56 +00:00
|
|
|
respErrEmptyPluginName = "empty plugin name"
|
|
|
|
respErrEmptyName = "empty name attribute given"
|
2017-04-13 00:35:02 +00:00
|
|
|
)
|
|
|
|
|
2017-04-24 20:59:12 +00:00
|
|
|
// DatabaseConfig is used by the Factory function to configure a Database
|
2017-04-13 17:33:34 +00:00
|
|
|
// object.
|
|
|
|
type DatabaseConfig struct {
|
|
|
|
PluginName string `json:"plugin_name" structs:"plugin_name" mapstructure:"plugin_name"`
|
|
|
|
// ConnectionDetails stores the database specific connection settings needed
|
|
|
|
// by each database type.
|
|
|
|
ConnectionDetails map[string]interface{} `json:"connection_details" structs:"connection_details" mapstructure:"connection_details"`
|
|
|
|
AllowedRoles []string `json:"allowed_roles" structs:"allowed_roles" mapstructure:"allowed_roles"`
|
2018-03-21 19:05:56 +00:00
|
|
|
|
|
|
|
RootCredentialsRotateStatements []string `json:"root_credentials_rotate_statements" structs:"root_credentials_rotate_statements" mapstructure:"root_credentials_rotate_statements"`
|
2020-09-18 21:10:54 +00:00
|
|
|
|
|
|
|
PasswordPolicy string `json:"password_policy" structs:"password_policy" mapstructure:"password_policy"`
|
2017-04-13 17:33:34 +00:00
|
|
|
}
|
|
|
|
|
2017-04-11 18:50:34 +00:00
|
|
|
// pathResetConnection configures a path to reset a plugin.
|
2017-02-16 00:51:59 +00:00
|
|
|
func pathResetConnection(b *databaseBackend) *framework.Path {
|
|
|
|
return &framework.Path{
|
|
|
|
Pattern: fmt.Sprintf("reset/%s", framework.GenericNameRegex("name")),
|
|
|
|
Fields: map[string]*framework.FieldSchema{
|
|
|
|
"name": &framework.FieldSchema{
|
|
|
|
Type: framework.TypeString,
|
2017-04-13 00:35:02 +00:00
|
|
|
Description: "Name of this database connection",
|
2017-02-16 00:51:59 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
Callbacks: map[logical.Operation]framework.OperationFunc{
|
2017-04-11 18:50:34 +00:00
|
|
|
logical.UpdateOperation: b.pathConnectionReset(),
|
2017-02-16 00:51:59 +00:00
|
|
|
},
|
|
|
|
|
2017-04-11 18:50:34 +00:00
|
|
|
HelpSynopsis: pathResetConnectionHelpSyn,
|
|
|
|
HelpDescription: pathResetConnectionHelpDesc,
|
2017-02-16 00:51:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-11 18:50:34 +00:00
|
|
|
// pathConnectionReset resets a plugin by closing the existing instance and
|
|
|
|
// creating a new one.
|
|
|
|
func (b *databaseBackend) pathConnectionReset() framework.OperationFunc {
|
2018-01-08 18:31:38 +00:00
|
|
|
return func(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
2017-04-11 18:50:34 +00:00
|
|
|
name := data.Get("name").(string)
|
|
|
|
if name == "" {
|
2017-05-01 22:30:56 +00:00
|
|
|
return logical.ErrorResponse(respErrEmptyName), nil
|
2017-04-11 18:50:34 +00:00
|
|
|
}
|
|
|
|
|
2017-04-13 00:35:02 +00:00
|
|
|
// Close plugin and delete the entry in the connections cache.
|
2018-03-21 19:05:56 +00:00
|
|
|
if err := b.ClearConnection(name); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-02-16 00:51:59 +00:00
|
|
|
|
2017-04-13 00:35:02 +00:00
|
|
|
// Execute plugin again, we don't need the object so throw away.
|
2018-03-21 19:05:56 +00:00
|
|
|
if _, err := b.GetConnection(ctx, req.Storage, name); err != nil {
|
2017-04-11 18:50:34 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2017-02-16 00:51:59 +00:00
|
|
|
|
2017-04-11 18:50:34 +00:00
|
|
|
return nil, nil
|
2017-03-13 21:39:55 +00:00
|
|
|
}
|
2017-02-16 00:51:59 +00:00
|
|
|
}
|
|
|
|
|
2017-03-22 00:19:30 +00:00
|
|
|
// pathConfigurePluginConnection returns a configured framework.Path setup to
|
|
|
|
// operate on plugins.
|
2017-03-10 05:31:29 +00:00
|
|
|
func pathConfigurePluginConnection(b *databaseBackend) *framework.Path {
|
2016-12-19 18:15:58 +00:00
|
|
|
return &framework.Path{
|
2017-04-11 01:38:34 +00:00
|
|
|
Pattern: fmt.Sprintf("config/%s", framework.GenericNameRegex("name")),
|
2016-12-19 18:15:58 +00:00
|
|
|
Fields: map[string]*framework.FieldSchema{
|
|
|
|
"name": &framework.FieldSchema{
|
|
|
|
Type: framework.TypeString,
|
2017-04-13 00:35:02 +00:00
|
|
|
Description: "Name of this database connection",
|
2016-12-19 18:15:58 +00:00
|
|
|
},
|
|
|
|
|
2017-04-04 00:52:29 +00:00
|
|
|
"plugin_name": &framework.FieldSchema{
|
2017-03-10 22:10:42 +00:00
|
|
|
Type: framework.TypeString,
|
2017-04-11 18:50:34 +00:00
|
|
|
Description: `The name of a builtin or previously registered
|
2017-04-13 17:33:34 +00:00
|
|
|
plugin known to vault. This endpoint will create an instance of
|
|
|
|
that plugin type.`,
|
2017-03-10 22:10:42 +00:00
|
|
|
},
|
2017-04-13 00:35:02 +00:00
|
|
|
|
|
|
|
"verify_connection": &framework.FieldSchema{
|
|
|
|
Type: framework.TypeBool,
|
|
|
|
Default: true,
|
|
|
|
Description: `If true, the connection details are verified by
|
2017-04-13 17:33:34 +00:00
|
|
|
actually connecting to the database. Defaults to true.`,
|
|
|
|
},
|
|
|
|
|
|
|
|
"allowed_roles": &framework.FieldSchema{
|
2017-04-25 17:26:23 +00:00
|
|
|
Type: framework.TypeCommaStringSlice,
|
|
|
|
Description: `Comma separated string or array of the role names
|
2017-04-25 18:48:24 +00:00
|
|
|
allowed to get creds from this database connection. If empty no
|
|
|
|
roles are allowed. If "*" all roles are allowed.`,
|
2017-04-13 00:35:02 +00:00
|
|
|
},
|
2018-03-21 19:05:56 +00:00
|
|
|
|
|
|
|
"root_rotation_statements": &framework.FieldSchema{
|
|
|
|
Type: framework.TypeStringSlice,
|
|
|
|
Description: `Specifies the database statements to be executed
|
|
|
|
to rotate the root user's credentials. See the plugin's API
|
|
|
|
page for more information on support and formatting for this
|
|
|
|
parameter.`,
|
|
|
|
},
|
2020-09-18 21:10:54 +00:00
|
|
|
"password_policy": &framework.FieldSchema{
|
|
|
|
Type: framework.TypeString,
|
|
|
|
Description: `Password policy to use when generating passwords.`,
|
|
|
|
},
|
2016-12-19 18:15:58 +00:00
|
|
|
},
|
|
|
|
|
2018-06-19 15:24:28 +00:00
|
|
|
ExistenceCheck: b.connectionExistenceCheck(),
|
2016-12-19 18:15:58 +00:00
|
|
|
Callbacks: map[logical.Operation]framework.OperationFunc{
|
2018-06-19 15:24:28 +00:00
|
|
|
logical.CreateOperation: b.connectionWriteHandler(),
|
2017-04-11 01:38:34 +00:00
|
|
|
logical.UpdateOperation: b.connectionWriteHandler(),
|
|
|
|
logical.ReadOperation: b.connectionReadHandler(),
|
|
|
|
logical.DeleteOperation: b.connectionDeleteHandler(),
|
2016-12-19 18:15:58 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
HelpSynopsis: pathConfigConnectionHelpSyn,
|
|
|
|
HelpDescription: pathConfigConnectionHelpDesc,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-19 15:24:28 +00:00
|
|
|
func (b *databaseBackend) connectionExistenceCheck() framework.ExistenceFunc {
|
|
|
|
return func(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) {
|
|
|
|
name := data.Get("name").(string)
|
|
|
|
if name == "" {
|
|
|
|
return false, errors.New(`missing "name" parameter`)
|
|
|
|
}
|
|
|
|
|
|
|
|
entry, err := req.Storage.Get(ctx, fmt.Sprintf("config/%s", name))
|
|
|
|
if err != nil {
|
2020-09-18 21:10:54 +00:00
|
|
|
return false, fmt.Errorf("failed to read connection configuration: %w", err)
|
2018-06-19 15:24:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return entry != nil, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-07 14:03:17 +00:00
|
|
|
func pathListPluginConnection(b *databaseBackend) *framework.Path {
|
|
|
|
return &framework.Path{
|
|
|
|
Pattern: fmt.Sprintf("config/?$"),
|
|
|
|
|
|
|
|
Callbacks: map[logical.Operation]framework.OperationFunc{
|
|
|
|
logical.ListOperation: b.connectionListHandler(),
|
|
|
|
},
|
|
|
|
|
|
|
|
HelpSynopsis: pathConfigConnectionHelpSyn,
|
|
|
|
HelpDescription: pathConfigConnectionHelpDesc,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *databaseBackend) connectionListHandler() framework.OperationFunc {
|
2018-01-08 18:31:38 +00:00
|
|
|
return func(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
2018-01-19 06:44:44 +00:00
|
|
|
entries, err := req.Storage.List(ctx, "config/")
|
2017-06-07 14:03:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return logical.ListResponse(entries), nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-04 00:37:34 +00:00
|
|
|
// connectionReadHandler reads out the connection configuration
|
2017-03-10 05:31:29 +00:00
|
|
|
func (b *databaseBackend) connectionReadHandler() framework.OperationFunc {
|
2018-01-08 18:31:38 +00:00
|
|
|
return func(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
2017-03-10 05:31:29 +00:00
|
|
|
name := data.Get("name").(string)
|
2017-04-13 00:35:02 +00:00
|
|
|
if name == "" {
|
2017-05-01 22:30:56 +00:00
|
|
|
return logical.ErrorResponse(respErrEmptyName), nil
|
2017-04-13 00:35:02 +00:00
|
|
|
}
|
2016-12-19 18:15:58 +00:00
|
|
|
|
2018-01-19 06:44:44 +00:00
|
|
|
entry, err := req.Storage.Get(ctx, fmt.Sprintf("config/%s", name))
|
2017-03-10 05:31:29 +00:00
|
|
|
if err != nil {
|
2020-09-18 21:10:54 +00:00
|
|
|
return nil, fmt.Errorf("failed to read connection configuration: %w", err)
|
2017-03-10 05:31:29 +00:00
|
|
|
}
|
|
|
|
if entry == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
2016-12-19 18:15:58 +00:00
|
|
|
|
2017-04-05 23:20:31 +00:00
|
|
|
var config DatabaseConfig
|
2017-03-10 05:31:29 +00:00
|
|
|
if err := entry.DecodeJSON(&config); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-03-30 14:17:39 +00:00
|
|
|
|
2018-04-07 15:06:04 +00:00
|
|
|
// Mask the password if it is in the url
|
|
|
|
if connURLRaw, ok := config.ConnectionDetails["connection_url"]; ok {
|
|
|
|
connURL := connURLRaw.(string)
|
|
|
|
if conn, err := url.Parse(connURL); err == nil {
|
|
|
|
if password, ok := conn.User.Password(); ok {
|
|
|
|
config.ConnectionDetails["connection_url"] = strings.Replace(connURL, password, "*****", -1)
|
|
|
|
}
|
|
|
|
}
|
2018-03-30 14:17:39 +00:00
|
|
|
}
|
|
|
|
|
2018-04-07 15:06:04 +00:00
|
|
|
delete(config.ConnectionDetails, "password")
|
2020-11-19 10:58:55 +00:00
|
|
|
delete(config.ConnectionDetails, "private_key")
|
2018-04-07 15:06:04 +00:00
|
|
|
|
2017-03-10 05:31:29 +00:00
|
|
|
return &logical.Response{
|
|
|
|
Data: structs.New(config).Map(),
|
|
|
|
}, nil
|
2016-12-19 18:15:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-22 00:19:30 +00:00
|
|
|
// connectionDeleteHandler deletes the connection configuration
|
|
|
|
func (b *databaseBackend) connectionDeleteHandler() framework.OperationFunc {
|
2018-01-08 18:31:38 +00:00
|
|
|
return func(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
2017-03-22 00:19:30 +00:00
|
|
|
name := data.Get("name").(string)
|
|
|
|
if name == "" {
|
2017-05-01 22:30:56 +00:00
|
|
|
return logical.ErrorResponse(respErrEmptyName), nil
|
2017-03-22 00:19:30 +00:00
|
|
|
}
|
|
|
|
|
2018-01-19 06:44:44 +00:00
|
|
|
err := req.Storage.Delete(ctx, fmt.Sprintf("config/%s", name))
|
2017-03-22 00:19:30 +00:00
|
|
|
if err != nil {
|
2019-11-11 17:04:24 +00:00
|
|
|
return nil, errwrap.Wrapf("failed to delete connection configuration: {{err}}", err)
|
2017-03-22 00:19:30 +00:00
|
|
|
}
|
|
|
|
|
2018-03-21 19:05:56 +00:00
|
|
|
if err := b.ClearConnection(name); err != nil {
|
|
|
|
return nil, err
|
2017-04-13 00:35:02 +00:00
|
|
|
}
|
2017-03-22 00:19:30 +00:00
|
|
|
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// connectionWriteHandler returns a handler function for creating and updating
|
|
|
|
// both builtin and plugin database types.
|
2017-04-05 23:20:31 +00:00
|
|
|
func (b *databaseBackend) connectionWriteHandler() framework.OperationFunc {
|
2018-01-08 18:31:38 +00:00
|
|
|
return func(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
2018-06-19 15:24:28 +00:00
|
|
|
verifyConnection := data.Get("verify_connection").(bool)
|
2016-12-19 18:15:58 +00:00
|
|
|
|
2017-03-10 05:31:29 +00:00
|
|
|
name := data.Get("name").(string)
|
2017-03-13 21:39:55 +00:00
|
|
|
if name == "" {
|
2017-05-01 22:30:56 +00:00
|
|
|
return logical.ErrorResponse(respErrEmptyName), nil
|
2017-03-13 21:39:55 +00:00
|
|
|
}
|
|
|
|
|
2018-06-19 15:24:28 +00:00
|
|
|
// Baseline
|
|
|
|
config := &DatabaseConfig{}
|
|
|
|
|
|
|
|
entry, err := req.Storage.Get(ctx, fmt.Sprintf("config/%s", name))
|
|
|
|
if err != nil {
|
2020-09-18 21:10:54 +00:00
|
|
|
return nil, fmt.Errorf("failed to read connection configuration: %w", err)
|
2018-06-19 15:24:28 +00:00
|
|
|
}
|
|
|
|
if entry != nil {
|
|
|
|
if err := entry.DecodeJSON(config); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if pluginNameRaw, ok := data.GetOk("plugin_name"); ok {
|
|
|
|
config.PluginName = pluginNameRaw.(string)
|
|
|
|
} else if req.Operation == logical.CreateOperation {
|
|
|
|
config.PluginName = data.Get("plugin_name").(string)
|
|
|
|
}
|
|
|
|
if config.PluginName == "" {
|
|
|
|
return logical.ErrorResponse(respErrEmptyPluginName), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if allowedRolesRaw, ok := data.GetOk("allowed_roles"); ok {
|
|
|
|
config.AllowedRoles = allowedRolesRaw.([]string)
|
|
|
|
} else if req.Operation == logical.CreateOperation {
|
|
|
|
config.AllowedRoles = data.Get("allowed_roles").([]string)
|
|
|
|
}
|
|
|
|
|
|
|
|
if rootRotationStatementsRaw, ok := data.GetOk("root_rotation_statements"); ok {
|
|
|
|
config.RootCredentialsRotateStatements = rootRotationStatementsRaw.([]string)
|
|
|
|
} else if req.Operation == logical.CreateOperation {
|
|
|
|
config.RootCredentialsRotateStatements = data.Get("root_rotation_statements").([]string)
|
|
|
|
}
|
2017-04-25 18:11:10 +00:00
|
|
|
|
2020-09-18 21:10:54 +00:00
|
|
|
if passwordPolicyRaw, ok := data.GetOk("password_policy"); ok {
|
|
|
|
config.PasswordPolicy = passwordPolicyRaw.(string)
|
|
|
|
}
|
|
|
|
|
2017-04-25 18:11:10 +00:00
|
|
|
// Remove these entries from the data before we store it keyed under
|
|
|
|
// ConnectionDetails.
|
|
|
|
delete(data.Raw, "name")
|
|
|
|
delete(data.Raw, "plugin_name")
|
|
|
|
delete(data.Raw, "allowed_roles")
|
|
|
|
delete(data.Raw, "verify_connection")
|
2018-03-21 19:05:56 +00:00
|
|
|
delete(data.Raw, "root_rotation_statements")
|
2020-09-18 21:10:54 +00:00
|
|
|
delete(data.Raw, "password_policy")
|
2017-04-13 17:33:34 +00:00
|
|
|
|
2020-09-18 21:10:54 +00:00
|
|
|
id, err := uuid.GenerateUUID()
|
2017-03-21 23:05:59 +00:00
|
|
|
if err != nil {
|
2020-09-18 21:10:54 +00:00
|
|
|
return nil, err
|
2017-03-21 23:05:59 +00:00
|
|
|
}
|
2018-06-19 15:24:28 +00:00
|
|
|
|
|
|
|
// If this is an update, take any new values, overwrite what was there
|
|
|
|
// before, and pass that in as the "new" set of values to the plugin,
|
|
|
|
// then save what results
|
|
|
|
if req.Operation == logical.CreateOperation {
|
|
|
|
config.ConnectionDetails = data.Raw
|
|
|
|
} else {
|
|
|
|
if config.ConnectionDetails == nil {
|
|
|
|
config.ConnectionDetails = make(map[string]interface{})
|
|
|
|
}
|
|
|
|
for k, v := range data.Raw {
|
|
|
|
config.ConnectionDetails[k] = v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-18 21:10:54 +00:00
|
|
|
// Create a database plugin and initialize it.
|
|
|
|
dbw, err := newDatabaseWrapper(ctx, config.PluginName, b.System(), b.logger)
|
2017-03-21 23:05:59 +00:00
|
|
|
if err != nil {
|
2020-09-18 21:10:54 +00:00
|
|
|
return logical.ErrorResponse("error creating database object: %s", err), nil
|
2016-12-19 18:15:58 +00:00
|
|
|
}
|
2017-02-16 00:51:59 +00:00
|
|
|
|
2020-10-15 19:20:12 +00:00
|
|
|
initReq := v5.InitializeRequest{
|
2020-09-18 21:10:54 +00:00
|
|
|
Config: config.ConnectionDetails,
|
|
|
|
VerifyConnection: verifyConnection,
|
|
|
|
}
|
|
|
|
initResp, err := dbw.Initialize(ctx, initReq)
|
|
|
|
if err != nil {
|
|
|
|
dbw.Close()
|
|
|
|
return logical.ErrorResponse("error creating database object: %s", err), nil
|
|
|
|
}
|
|
|
|
config.ConnectionDetails = initResp.Config
|
|
|
|
|
2017-04-13 00:35:02 +00:00
|
|
|
b.Lock()
|
|
|
|
defer b.Unlock()
|
|
|
|
|
2017-04-26 22:55:34 +00:00
|
|
|
// Close and remove the old connection
|
|
|
|
b.clearConnection(name)
|
2016-12-19 18:15:58 +00:00
|
|
|
|
2018-03-21 19:05:56 +00:00
|
|
|
b.connections[name] = &dbPluginInstance{
|
2020-09-18 21:10:54 +00:00
|
|
|
database: dbw,
|
2018-03-21 19:05:56 +00:00
|
|
|
name: name,
|
|
|
|
id: id,
|
|
|
|
}
|
2017-04-04 01:30:38 +00:00
|
|
|
|
2020-09-18 21:10:54 +00:00
|
|
|
err = storeConfig(ctx, req.Storage, name, config)
|
2017-03-08 22:46:53 +00:00
|
|
|
if err != nil {
|
2017-03-10 05:31:29 +00:00
|
|
|
return nil, err
|
2017-03-08 22:46:53 +00:00
|
|
|
}
|
2016-12-19 18:15:58 +00:00
|
|
|
|
2017-03-10 05:31:29 +00:00
|
|
|
resp := &logical.Response{}
|
2018-04-07 15:06:04 +00:00
|
|
|
|
|
|
|
// This is a simple test to to check for passwords in the connection_url paramater. If one exists,
|
|
|
|
// warn the user to use templated url string
|
|
|
|
if connURLRaw, ok := config.ConnectionDetails["connection_url"]; ok {
|
|
|
|
if connURL, err := url.Parse(connURLRaw.(string)); err == nil {
|
|
|
|
if _, ok := connURL.User.Password(); ok {
|
|
|
|
resp.AddWarning("Password found in connection_url, use a templated url to enable root rotation and prevent read access to password information.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-12-19 18:15:58 +00:00
|
|
|
|
2020-09-18 21:10:54 +00:00
|
|
|
// If using a legacy DB plugin and set the `password_policy` field, send a warning to the user indicating
|
|
|
|
// the `password_policy` will not be used
|
|
|
|
if dbw.isV4() && config.PasswordPolicy != "" {
|
|
|
|
resp.AddWarning(fmt.Sprintf("%s does not support password policies - upgrade to the latest version of "+
|
|
|
|
"Vault (or the sdk if using a custom plugin) to gain password policy support", config.PluginName))
|
|
|
|
}
|
|
|
|
|
2017-03-10 05:31:29 +00:00
|
|
|
return resp, nil
|
|
|
|
}
|
2016-12-19 18:15:58 +00:00
|
|
|
}
|
|
|
|
|
2020-09-18 21:10:54 +00:00
|
|
|
func storeConfig(ctx context.Context, storage logical.Storage, name string, config *DatabaseConfig) error {
|
|
|
|
entry, err := logical.StorageEntryJSON(fmt.Sprintf("config/%s", name), config)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to marshal object to JSON: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = storage.Put(ctx, entry)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to save object: %w", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-12-19 18:15:58 +00:00
|
|
|
const pathConfigConnectionHelpSyn = `
|
2017-04-11 18:50:34 +00:00
|
|
|
Configure connection details to a database plugin.
|
2016-12-19 18:15:58 +00:00
|
|
|
`
|
|
|
|
|
|
|
|
const pathConfigConnectionHelpDesc = `
|
2017-04-11 18:50:34 +00:00
|
|
|
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.
|
2016-12-19 18:15:58 +00:00
|
|
|
|
2017-05-04 00:37:34 +00:00
|
|
|
In addition to the database specific connection details, this endpoint also
|
2017-04-11 18:50:34 +00:00
|
|
|
accepts:
|
|
|
|
|
|
|
|
* "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.
|
|
|
|
|
2017-04-13 00:35:02 +00:00
|
|
|
* "verify_connection" (default: true) - A boolean value denoting if the plugin should verify
|
2017-04-11 18:50:34 +00:00
|
|
|
it is able to connect to the database using the provided connection
|
|
|
|
details.
|
|
|
|
`
|
|
|
|
|
|
|
|
const pathResetConnectionHelpSyn = `
|
|
|
|
Resets a database plugin.
|
|
|
|
`
|
2016-12-19 18:15:58 +00:00
|
|
|
|
2017-04-11 18:50:34 +00:00
|
|
|
const pathResetConnectionHelpDesc = `
|
|
|
|
This path resets the database connection by closing the existing database plugin
|
|
|
|
instance and running a new one.
|
2016-12-19 18:15:58 +00:00
|
|
|
`
|