Skip to content

Commit

Permalink
Use the role name in the db username (#2812)
Browse files Browse the repository at this point in the history
  • Loading branch information
briankassouf authored and jefferai committed Jun 6, 2017
1 parent 2631bde commit abc9001
Show file tree
Hide file tree
Showing 24 changed files with 291 additions and 147 deletions.
4 changes: 2 additions & 2 deletions builtin/logical/database/dbplugin/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ func (dr *databasePluginRPCClient) Type() (string, error) {
return fmt.Sprintf("plugin-%s", dbType), err
}

func (dr *databasePluginRPCClient) CreateUser(statements Statements, usernamePrefix string, expiration time.Time) (username string, password string, err error) {
func (dr *databasePluginRPCClient) CreateUser(statements Statements, usernameConfig UsernameConfig, expiration time.Time) (username string, password string, err error) {
req := CreateUserRequest{
Statements: statements,
UsernamePrefix: usernamePrefix,
UsernameConfig: usernameConfig,
Expiration: expiration,
}

Expand Down
8 changes: 4 additions & 4 deletions builtin/logical/database/dbplugin/databasemiddleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ func (mw *databaseTracingMiddleware) Type() (string, error) {
return mw.next.Type()
}

func (mw *databaseTracingMiddleware) CreateUser(statements Statements, usernamePrefix string, expiration time.Time) (username string, password string, err error) {
func (mw *databaseTracingMiddleware) CreateUser(statements Statements, usernameConfig UsernameConfig, expiration time.Time) (username string, password string, err error) {
defer func(then time.Time) {
mw.logger.Trace("database", "operation", "CreateUser", "status", "finished", "type", mw.typeStr, "err", err, "took", time.Since(then))
}(time.Now())

mw.logger.Trace("database", "operation", "CreateUser", "status", "started", "type", mw.typeStr)
return mw.next.CreateUser(statements, usernamePrefix, expiration)
return mw.next.CreateUser(statements, usernameConfig, expiration)
}

func (mw *databaseTracingMiddleware) RenewUser(statements Statements, username string, expiration time.Time) (err error) {
Expand Down Expand Up @@ -81,7 +81,7 @@ func (mw *databaseMetricsMiddleware) Type() (string, error) {
return mw.next.Type()
}

func (mw *databaseMetricsMiddleware) CreateUser(statements Statements, usernamePrefix string, expiration time.Time) (username string, password string, err error) {
func (mw *databaseMetricsMiddleware) CreateUser(statements Statements, usernameConfig UsernameConfig, expiration time.Time) (username string, password string, err error) {
defer func(now time.Time) {
metrics.MeasureSince([]string{"database", "CreateUser"}, now)
metrics.MeasureSince([]string{"database", mw.typeStr, "CreateUser"}, now)
Expand All @@ -94,7 +94,7 @@ func (mw *databaseMetricsMiddleware) CreateUser(statements Statements, usernameP

metrics.IncrCounter([]string{"database", "CreateUser"}, 1)
metrics.IncrCounter([]string{"database", mw.typeStr, "CreateUser"}, 1)
return mw.next.CreateUser(statements, usernamePrefix, expiration)
return mw.next.CreateUser(statements, usernameConfig, expiration)
}

func (mw *databaseMetricsMiddleware) RenewUser(statements Statements, username string, expiration time.Time) (err error) {
Expand Down
13 changes: 10 additions & 3 deletions builtin/logical/database/dbplugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
// Database is the interface that all database objects must implement.
type Database interface {
Type() (string, error)
CreateUser(statements Statements, usernamePrefix string, expiration time.Time) (username string, password string, err error)
CreateUser(statements Statements, usernameConfig UsernameConfig, expiration time.Time) (username string, password string, err error)
RenewUser(statements Statements, username string, expiration time.Time) error
RevokeUser(statements Statements, username string) error

Expand All @@ -29,6 +29,13 @@ type Statements struct {
RenewStatements string `json:"renew_statements" mapstructure:"renew_statements" structs:"renew_statements"`
}

// UsernameConfig is used to configure prefixes for the username to be
// generated.
type UsernameConfig struct {
DisplayName string
RoleName string
}

// PluginFactory is used to build plugin database types. It wraps the database
// object in a logging and metrics middleware.
func PluginFactory(pluginName string, sys pluginutil.LookRunnerUtil, logger log.Logger) (Database, error) {
Expand Down Expand Up @@ -89,7 +96,7 @@ func PluginFactory(pluginName string, sys pluginutil.LookRunnerUtil, logger log.
// This prevents users from executing bad plugins or executing a plugin
// directory. It is a UX feature, not a security feature.
var handshakeConfig = plugin.HandshakeConfig{
ProtocolVersion: 1,
ProtocolVersion: 2,
MagicCookieKey: "VAULT_DATABASE_PLUGIN",
MagicCookieValue: "926a0820-aea2-be28-51d6-83cdf00e8edb",
}
Expand Down Expand Up @@ -117,7 +124,7 @@ type InitializeRequest struct {

type CreateUserRequest struct {
Statements Statements
UsernamePrefix string
UsernameConfig UsernameConfig
Expiration time.Time
}

Expand Down
35 changes: 25 additions & 10 deletions builtin/logical/database/dbplugin/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ type mockPlugin struct {
}

func (m *mockPlugin) Type() (string, error) { return "mock", nil }
func (m *mockPlugin) CreateUser(statements dbplugin.Statements, usernamePrefix string, expiration time.Time) (username string, password string, err error) {
func (m *mockPlugin) CreateUser(statements dbplugin.Statements, usernameConf dbplugin.UsernameConfig, expiration time.Time) (username string, password string, err error) {
err = errors.New("err")
if usernamePrefix == "" || expiration.IsZero() {
if usernameConf.DisplayName == "" || expiration.IsZero() {
return "", "", err
}

if _, ok := m.users[usernamePrefix]; ok {
if _, ok := m.users[usernameConf.DisplayName]; ok {
return "", "", err
}

m.users[usernamePrefix] = []string{password}
m.users[usernameConf.DisplayName] = []string{password}

return usernamePrefix, "test", nil
return usernameConf.DisplayName, "test", nil
}
func (m *mockPlugin) RenewUser(statements dbplugin.Statements, username string, expiration time.Time) error {
err := errors.New("err")
Expand Down Expand Up @@ -162,7 +162,12 @@ func TestPlugin_CreateUser(t *testing.T) {
t.Fatalf("err: %s", err)
}

us, pw, err := db.CreateUser(dbplugin.Statements{}, "test", time.Now().Add(time.Minute))
usernameConf := dbplugin.UsernameConfig{
DisplayName: "test",
RoleName: "test",
}

us, pw, err := db.CreateUser(dbplugin.Statements{}, usernameConf, time.Now().Add(time.Minute))
if err != nil {
t.Fatalf("err: %s", err)
}
Expand All @@ -172,7 +177,7 @@ func TestPlugin_CreateUser(t *testing.T) {

// try and save the same user again to verify it saved the first time, this
// should return an error
_, _, err = db.CreateUser(dbplugin.Statements{}, "test", time.Now().Add(time.Minute))
_, _, err = db.CreateUser(dbplugin.Statements{}, usernameConf, time.Now().Add(time.Minute))
if err == nil {
t.Fatal("expected an error, user wasn't created correctly")
}
Expand All @@ -198,7 +203,12 @@ func TestPlugin_RenewUser(t *testing.T) {
t.Fatalf("err: %s", err)
}

us, _, err := db.CreateUser(dbplugin.Statements{}, "test", time.Now().Add(time.Minute))
usernameConf := dbplugin.UsernameConfig{
DisplayName: "test",
RoleName: "test",
}

us, _, err := db.CreateUser(dbplugin.Statements{}, usernameConf, time.Now().Add(time.Minute))
if err != nil {
t.Fatalf("err: %s", err)
}
Expand Down Expand Up @@ -229,7 +239,12 @@ func TestPlugin_RevokeUser(t *testing.T) {
t.Fatalf("err: %s", err)
}

us, _, err := db.CreateUser(dbplugin.Statements{}, "test", time.Now().Add(time.Minute))
usernameConf := dbplugin.UsernameConfig{
DisplayName: "test",
RoleName: "test",
}

us, _, err := db.CreateUser(dbplugin.Statements{}, usernameConf, time.Now().Add(time.Minute))
if err != nil {
t.Fatalf("err: %s", err)
}
Expand All @@ -241,7 +256,7 @@ func TestPlugin_RevokeUser(t *testing.T) {
}

// Try adding the same username back so we can verify it was removed
_, _, err = db.CreateUser(dbplugin.Statements{}, "test", time.Now().Add(time.Minute))
_, _, err = db.CreateUser(dbplugin.Statements{}, usernameConf, time.Now().Add(time.Minute))
if err != nil {
t.Fatalf("err: %s", err)
}
Expand Down
2 changes: 1 addition & 1 deletion builtin/logical/database/dbplugin/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (ds *databasePluginRPCServer) Type(_ struct{}, resp *string) error {

func (ds *databasePluginRPCServer) CreateUser(args *CreateUserRequest, resp *CreateUserResponse) error {
var err error
resp.Username, resp.Password, err = ds.impl.CreateUser(args.Statements, args.UsernamePrefix, args.Expiration)
resp.Username, resp.Password, err = ds.impl.CreateUser(args.Statements, args.UsernameConfig, args.Expiration)

return err
}
Expand Down
8 changes: 7 additions & 1 deletion builtin/logical/database/path_creds_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"time"

"github.com/hashicorp/vault/builtin/logical/database/dbplugin"
"github.com/hashicorp/vault/helper/strutil"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
Expand Down Expand Up @@ -74,8 +75,13 @@ func (b *databaseBackend) pathCredsCreateRead() framework.OperationFunc {

expiration := time.Now().Add(role.DefaultTTL)

usernameConfig := dbplugin.UsernameConfig{
DisplayName: req.DisplayName,
RoleName: name,
}

// Create the user
username, password, err := db.CreateUser(role.Statements, req.DisplayName, expiration)
username, password, err := db.CreateUser(role.Statements, usernameConfig, expiration)
// Unlock
unlockFunc()
if err != nil {
Expand Down
8 changes: 4 additions & 4 deletions helper/builtinplugins/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ type BuiltinFactory func() (interface{}, error)
var plugins map[string]BuiltinFactory = map[string]BuiltinFactory{
// These four plugins all use the same mysql implementation but with
// different username settings passed by the constructor.
"mysql-database-plugin": mysql.New(mysql.DisplayNameLen, mysql.UsernameLen),
"mysql-aurora-database-plugin": mysql.New(mysql.LegacyDisplayNameLen, mysql.LegacyUsernameLen),
"mysql-rds-database-plugin": mysql.New(mysql.LegacyDisplayNameLen, mysql.LegacyUsernameLen),
"mysql-legacy-database-plugin": mysql.New(mysql.LegacyDisplayNameLen, mysql.LegacyUsernameLen),
"mysql-database-plugin": mysql.New(mysql.MetadataLen, mysql.UsernameLen),
"mysql-aurora-database-plugin": mysql.New(mysql.LegacyMetadataLen, mysql.LegacyUsernameLen),
"mysql-rds-database-plugin": mysql.New(mysql.LegacyMetadataLen, mysql.LegacyUsernameLen),
"mysql-legacy-database-plugin": mysql.New(mysql.LegacyMetadataLen, mysql.LegacyUsernameLen),

"postgresql-database-plugin": postgresql.New,
"mssql-database-plugin": mssql.New,
Expand Down
13 changes: 10 additions & 3 deletions plugins/database/cassandra/cassandra.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ func New() (interface{}, error) {
connProducer := &cassandraConnectionProducer{}
connProducer.Type = cassandraTypeName

credsProducer := &cassandraCredentialsProducer{}
credsProducer := &credsutil.SQLCredentialsProducer{
DisplayNameLen: 15,
RoleNameLen: 15,
UsernameLen: 100,
Separator: "_",
}

dbType := &Cassandra{
ConnectionProducer: connProducer,
Expand Down Expand Up @@ -70,7 +75,7 @@ func (c *Cassandra) getConnection() (*gocql.Session, error) {

// CreateUser generates the username/password on the underlying Cassandra secret backend as instructed by
// the CreationStatement provided.
func (c *Cassandra) CreateUser(statements dbplugin.Statements, usernamePrefix string, expiration time.Time) (username string, password string, err error) {
func (c *Cassandra) CreateUser(statements dbplugin.Statements, usernameConfig dbplugin.UsernameConfig, expiration time.Time) (username string, password string, err error) {
// Grab the lock
c.Lock()
defer c.Unlock()
Expand All @@ -90,10 +95,12 @@ func (c *Cassandra) CreateUser(statements dbplugin.Statements, usernamePrefix st
rollbackCQL = defaultUserDeletionCQL
}

username, err = c.GenerateUsername(usernamePrefix)
username, err = c.GenerateUsername(usernameConfig)
if err != nil {
return "", "", err
}
// Cassandra doesn't like the uppercase usernames
username = strings.ToLower(username)

password, err = c.GeneratePassword()
if err != nil {
Expand Down
21 changes: 18 additions & 3 deletions plugins/database/cassandra/cassandra_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,12 @@ func TestCassandra_CreateUser(t *testing.T) {
CreationStatements: testCassandraRole,
}

username, password, err := db.CreateUser(statements, "test", time.Now().Add(time.Minute))
usernameConfig := dbplugin.UsernameConfig{
DisplayName: "test",
RoleName: "test",
}

username, password, err := db.CreateUser(statements, usernameConfig, time.Now().Add(time.Minute))
if err != nil {
t.Fatalf("err: %s", err)
}
Expand Down Expand Up @@ -161,7 +166,12 @@ func TestMyCassandra_RenewUser(t *testing.T) {
CreationStatements: testCassandraRole,
}

username, password, err := db.CreateUser(statements, "test", time.Now().Add(time.Minute))
usernameConfig := dbplugin.UsernameConfig{
DisplayName: "test",
RoleName: "test",
}

username, password, err := db.CreateUser(statements, usernameConfig, time.Now().Add(time.Minute))
if err != nil {
t.Fatalf("err: %s", err)
}
Expand Down Expand Up @@ -201,7 +211,12 @@ func TestCassandra_RevokeUser(t *testing.T) {
CreationStatements: testCassandraRole,
}

username, password, err := db.CreateUser(statements, "test", time.Now().Add(time.Minute))
usernameConfig := dbplugin.UsernameConfig{
DisplayName: "test",
RoleName: "test",
}

username, password, err := db.CreateUser(statements, usernameConfig, time.Now().Add(time.Minute))
if err != nil {
t.Fatalf("err: %s", err)
}
Expand Down
37 changes: 0 additions & 37 deletions plugins/database/cassandra/credentials_producer.go

This file was deleted.

36 changes: 0 additions & 36 deletions plugins/database/mongodb/credentials_producer.go

This file was deleted.

Loading

0 comments on commit abc9001

Please sign in to comment.