e4832fdbcf
* redoing connection handling * a little more cleanup * empty implementation of rotation * updating rotate signature * signature update * updating interfaces again :( * changing back to interface * adding templated url support and rotation for postgres * adding correct username * return updates * updating statements to be a list * adding error sanitizing middleware * fixing log sanitizier * adding postgres rotate test * removing conf from rotate * adding rotate command * adding mysql rotate * finishing up the endpoint in the db backend for rotate * no more structs, just store raw config * fixing tests * adding db instance lock * adding support for statement list in cassandra * wip redoing interface to support BC * adding falllback for Initialize implementation * adding backwards compat for statements * fix tests * fix more tests * fixing up tests, switching to new fields in statements * fixing more tests * adding mssql and mysql * wrapping all the things in middleware, implementing templating for mongodb * wrapping all db servers with error santizer * fixing test * store the name with the db instance * adding rotate to cassandra * adding compatibility translation to both server and plugin * reordering a few things * store the name with the db instance * reordering * adding a few more tests * switch secret values from slice to map * addressing some feedback * reinstate execute plugin after resetting connection * set database connection to closed * switching secret values func to map[string]interface for potential future uses * addressing feedback
198 lines
5.3 KiB
Go
198 lines
5.3 KiB
Go
package dbplugin
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/rpc"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// ---- RPC server domain ----
|
|
|
|
// databasePluginRPCServer implements an RPC version of Database and is run
|
|
// inside a plugin. It wraps an underlying implementation of Database.
|
|
type databasePluginRPCServer struct {
|
|
impl Database
|
|
}
|
|
|
|
func (ds *databasePluginRPCServer) Type(_ struct{}, resp *string) error {
|
|
var err error
|
|
*resp, err = ds.impl.Type()
|
|
return err
|
|
}
|
|
|
|
func (ds *databasePluginRPCServer) CreateUser(args *CreateUserRequestRPC, resp *CreateUserResponse) error {
|
|
var err error
|
|
resp.Username, resp.Password, err = ds.impl.CreateUser(context.Background(), args.Statements, args.UsernameConfig, args.Expiration)
|
|
return err
|
|
}
|
|
|
|
func (ds *databasePluginRPCServer) RenewUser(args *RenewUserRequestRPC, _ *struct{}) error {
|
|
err := ds.impl.RenewUser(context.Background(), args.Statements, args.Username, args.Expiration)
|
|
return err
|
|
}
|
|
|
|
func (ds *databasePluginRPCServer) RevokeUser(args *RevokeUserRequestRPC, _ *struct{}) error {
|
|
err := ds.impl.RevokeUser(context.Background(), args.Statements, args.Username)
|
|
return err
|
|
}
|
|
|
|
func (ds *databasePluginRPCServer) RotateRootCredentials(args *RotateRootCredentialsRequestRPC, resp *RotateRootCredentialsResponse) error {
|
|
config, err := ds.impl.RotateRootCredentials(context.Background(), args.Statements)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
resp.Config, err = json.Marshal(config)
|
|
return err
|
|
}
|
|
|
|
func (ds *databasePluginRPCServer) Initialize(args *InitializeRequestRPC, _ *struct{}) error {
|
|
return ds.Init(&InitRequestRPC{
|
|
Config: args.Config,
|
|
VerifyConnection: args.VerifyConnection,
|
|
}, &InitResponse{})
|
|
}
|
|
|
|
func (ds *databasePluginRPCServer) Init(args *InitRequestRPC, resp *InitResponse) error {
|
|
config, err := ds.impl.Init(context.Background(), args.Config, args.VerifyConnection)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
resp.Config, err = json.Marshal(config)
|
|
return err
|
|
}
|
|
|
|
func (ds *databasePluginRPCServer) Close(_ struct{}, _ *struct{}) error {
|
|
ds.impl.Close()
|
|
return nil
|
|
}
|
|
|
|
// ---- RPC client domain ----
|
|
// databasePluginRPCClient implements Database and is used on the client to
|
|
// make RPC calls to a plugin.
|
|
type databasePluginRPCClient struct {
|
|
client *rpc.Client
|
|
}
|
|
|
|
func (dr *databasePluginRPCClient) Type() (string, error) {
|
|
var dbType string
|
|
err := dr.client.Call("Plugin.Type", struct{}{}, &dbType)
|
|
|
|
return fmt.Sprintf("plugin-%s", dbType), err
|
|
}
|
|
|
|
func (dr *databasePluginRPCClient) CreateUser(_ context.Context, statements Statements, usernameConfig UsernameConfig, expiration time.Time) (username string, password string, err error) {
|
|
req := CreateUserRequestRPC{
|
|
Statements: statements,
|
|
UsernameConfig: usernameConfig,
|
|
Expiration: expiration,
|
|
}
|
|
|
|
var resp CreateUserResponse
|
|
err = dr.client.Call("Plugin.CreateUser", req, &resp)
|
|
|
|
return resp.Username, resp.Password, err
|
|
}
|
|
|
|
func (dr *databasePluginRPCClient) RenewUser(_ context.Context, statements Statements, username string, expiration time.Time) error {
|
|
req := RenewUserRequestRPC{
|
|
Statements: statements,
|
|
Username: username,
|
|
Expiration: expiration,
|
|
}
|
|
|
|
return dr.client.Call("Plugin.RenewUser", req, &struct{}{})
|
|
}
|
|
|
|
func (dr *databasePluginRPCClient) RevokeUser(_ context.Context, statements Statements, username string) error {
|
|
req := RevokeUserRequestRPC{
|
|
Statements: statements,
|
|
Username: username,
|
|
}
|
|
|
|
return dr.client.Call("Plugin.RevokeUser", req, &struct{}{})
|
|
}
|
|
|
|
func (dr *databasePluginRPCClient) RotateRootCredentials(_ context.Context, statements []string) (saveConf map[string]interface{}, err error) {
|
|
req := RotateRootCredentialsRequestRPC{
|
|
Statements: statements,
|
|
}
|
|
|
|
var resp RotateRootCredentialsResponse
|
|
err = dr.client.Call("Plugin.RotateRootCredentials", req, &resp)
|
|
|
|
err = json.Unmarshal(resp.Config, &saveConf)
|
|
return saveConf, err
|
|
}
|
|
|
|
func (dr *databasePluginRPCClient) Initialize(_ context.Context, conf map[string]interface{}, verifyConnection bool) error {
|
|
_, err := dr.Init(nil, conf, verifyConnection)
|
|
return err
|
|
}
|
|
|
|
func (dr *databasePluginRPCClient) Init(_ context.Context, conf map[string]interface{}, verifyConnection bool) (saveConf map[string]interface{}, err error) {
|
|
req := InitRequestRPC{
|
|
Config: conf,
|
|
VerifyConnection: verifyConnection,
|
|
}
|
|
|
|
var resp InitResponse
|
|
err = dr.client.Call("Plugin.Init", req, &resp)
|
|
if err != nil {
|
|
if strings.Contains(err.Error(), "can't find method Plugin.Init") {
|
|
req := InitializeRequestRPC{
|
|
Config: conf,
|
|
VerifyConnection: verifyConnection,
|
|
}
|
|
|
|
err = dr.client.Call("Plugin.Initialize", req, &struct{}{})
|
|
if err == nil {
|
|
return conf, nil
|
|
}
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
err = json.Unmarshal(resp.Config, &saveConf)
|
|
return saveConf, err
|
|
}
|
|
|
|
func (dr *databasePluginRPCClient) Close() error {
|
|
return dr.client.Call("Plugin.Close", struct{}{}, &struct{}{})
|
|
}
|
|
|
|
// ---- RPC Request Args Domain ----
|
|
|
|
type InitializeRequestRPC struct {
|
|
Config map[string]interface{}
|
|
VerifyConnection bool
|
|
}
|
|
|
|
type InitRequestRPC struct {
|
|
Config map[string]interface{}
|
|
VerifyConnection bool
|
|
}
|
|
|
|
type CreateUserRequestRPC struct {
|
|
Statements Statements
|
|
UsernameConfig UsernameConfig
|
|
Expiration time.Time
|
|
}
|
|
|
|
type RenewUserRequestRPC struct {
|
|
Statements Statements
|
|
Username string
|
|
Expiration time.Time
|
|
}
|
|
|
|
type RevokeUserRequestRPC struct {
|
|
Statements Statements
|
|
Username string
|
|
}
|
|
|
|
type RotateRootCredentialsRequestRPC struct {
|
|
Statements []string
|
|
}
|