Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the role name in the db username #2812

Merged
merged 6 commits into from
Jun 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would be a case where DisplayName and RoleName are different?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Display names are tied to tokens- the vault user who created the cred. Role name is the name of the database role that created the cred

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, so the role name (and unix timestamp) is now included as part of the username for more verbosity as to who and when the token was created?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct!

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,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bumping this means all existing plugins will need to recompile and probably update their code.

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