Add OSS stub functions for Self-Managed Static Roles (#28199)

This commit is contained in:
vinay-gopalan
2024-08-29 10:01:01 -07:00
committed by GitHub
parent 78e1cceccc
commit ec9b675f70
17 changed files with 445 additions and 126 deletions

View File

@@ -9,9 +9,8 @@ import (
"strconv"
"time"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"

View File

@@ -17,13 +17,12 @@ import (
"net/url"
"strings"
"github.com/hashicorp/vault/sdk/helper/locksutil"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/certutil"
"github.com/hashicorp/vault/sdk/helper/cidrutil"
"github.com/hashicorp/vault/sdk/helper/locksutil"
"github.com/hashicorp/vault/sdk/helper/ocsp"
"github.com/hashicorp/vault/sdk/helper/policyutil"
"github.com/hashicorp/vault/sdk/logical"

View File

@@ -217,6 +217,11 @@ func staticFields() map[string]*framework.FieldSchema {
this functionality. See the plugin's API page for more information on
support and formatting for this parameter.`,
},
"self_managed_password": {
Type: framework.TypeString,
Description: `Used to connect to a self-managed static account. Must
be provided by the user when root credentials are not provided.`,
},
}
return fields
}
@@ -628,6 +633,10 @@ func (b *databaseBackend) pathStaticRoleCreateUpdate(ctx context.Context, req *l
}
}
if smPasswordRaw, ok := data.GetOk("self_managed_password"); ok && createRole {
role.StaticAccount.SelfManagedPassword = smPasswordRaw.(string)
}
var credentialConfig map[string]string
if raw, ok := data.GetOk("credential_config"); ok {
credentialConfig = raw.(map[string]string)
@@ -785,6 +794,12 @@ type staticAccount struct {
// Username to create or assume management for static accounts
Username string `json:"username"`
// SelfManagedPassword is used to make a dedicated connection to the DB
// user specified by Username. The credentials will leverage the existing
// static role mechanisms to handle password rotations. Required when root
// credentials are not provided.
SelfManagedPassword string `json:"self_managed_password"`
// Password is the current password credential for static accounts. As an input,
// this is used/required when trying to assume management of an existing static
// account. Returned on credential request if the role's credential type is

View File

@@ -413,6 +413,11 @@ func (b *databaseBackend) setStaticAccount(ctx context.Context, s logical.Storag
Commands: input.Role.Statements.Rotation,
}
// Add external password to request so we can use static account connection
if input.Role.StaticAccount.SelfManagedPassword != "" {
updateReq.SelfManagedPassword = input.Role.StaticAccount.SelfManagedPassword
}
// Use credential from input if available. This happens if we're restoring from
// a WAL item or processing the rotation queue with an item that has a WAL
// associated with it
@@ -529,6 +534,12 @@ func (b *databaseBackend) setStaticAccount(ctx context.Context, s logical.Storag
}
modified = true
// static user password successfully updated in external system
// update self-managed password if available for future connections
if input.Role.StaticAccount.SelfManagedPassword != "" {
input.Role.StaticAccount.SelfManagedPassword = input.Role.StaticAccount.Password
}
// Store updated role information
// lvr is the known LastVaultRotation
lvr := time.Now()

3
changelog/28199.txt Normal file
View File

@@ -0,0 +1,3 @@
```release-note:feature
**Self-Managed Static Roles**: Self-Managed Static Roles are now supported for select SQL database engines (Postgres, Oracle). Requires Vault Enterprise.
```

View File

@@ -50,6 +50,10 @@ func PrepareTestContainer(t *testing.T) (func(), string) {
return cleanup, url
}
func PrepareTestContainerSelfManaged(t *testing.T) (func(), *url.URL) {
return prepareTestContainerSelfManaged(t, defaultRunOpts(t), defaultPGPass, true, false, false)
}
func PrepareTestContainerMultiHost(t *testing.T) (func(), string) {
_, cleanup, url, _ := prepareTestContainer(t, defaultRunOpts(t), defaultPGPass, true, false, true)
@@ -198,6 +202,25 @@ func prepareTestContainer(t *testing.T, runOpts docker.RunOptions, password stri
return runner, svc.Cleanup, svc.Config.URL().String(), containerID
}
func prepareTestContainerSelfManaged(t *testing.T, runOpts docker.RunOptions, password string, addSuffix, forceLocalAddr, useFallback bool,
) (func(), *url.URL) {
if os.Getenv("PG_URL") != "" {
return func() {}, nil
}
runner, err := docker.NewServiceRunner(runOpts)
if err != nil {
t.Fatalf("Could not start docker Postgres: %s", err)
}
svc, _, err := runner.StartNewService(context.Background(), addSuffix, forceLocalAddr, connectPostgres(password, runOpts.ImageRepo, useFallback))
if err != nil {
t.Fatalf("Could not start docker Postgres: %s", err)
}
return svc.Cleanup, svc.Config.URL()
}
func getPostgresSSLConfig(t *testing.T, host, sslMode, caCert, clientCert, clientKey string, useFallback bool) docker.ServiceConfig {
if useFallback {
// set the first host to a bad address so we can test the fallback logic

View File

@@ -199,6 +199,15 @@ func (p *PostgreSQL) getConnection(ctx context.Context) (*sql.DB, error) {
return db.(*sql.DB), nil
}
func (p *PostgreSQL) getStaticConnection(ctx context.Context, username, password string) (*sql.DB, error) {
db, err := p.StaticConnection(ctx, username, password)
if err != nil {
return nil, err
}
return db, nil
}
func (p *PostgreSQL) UpdateUser(ctx context.Context, req dbplugin.UpdateUserRequest) (dbplugin.UpdateUserResponse, error) {
if req.Username == "" {
return dbplugin.UpdateUserResponse{}, fmt.Errorf("missing username")
@@ -209,17 +218,17 @@ func (p *PostgreSQL) UpdateUser(ctx context.Context, req dbplugin.UpdateUserRequ
merr := &multierror.Error{}
if req.Password != nil {
err := p.changeUserPassword(ctx, req.Username, req.Password)
err := p.changeUserPassword(ctx, req.Username, req.Password, req.SelfManagedPassword)
merr = multierror.Append(merr, err)
}
if req.Expiration != nil {
err := p.changeUserExpiration(ctx, req.Username, req.Expiration)
err := p.changeUserExpiration(ctx, req.Username, req.Expiration, req.SelfManagedPassword)
merr = multierror.Append(merr, err)
}
return dbplugin.UpdateUserResponse{}, merr.ErrorOrNil()
}
func (p *PostgreSQL) changeUserPassword(ctx context.Context, username string, changePass *dbplugin.ChangePassword) error {
func (p *PostgreSQL) changeUserPassword(ctx context.Context, username string, changePass *dbplugin.ChangePassword, selfManagedPass string) error {
stmts := changePass.Statements.Commands
if len(stmts) == 0 {
stmts = []string{defaultChangePasswordStatement}
@@ -233,10 +242,19 @@ func (p *PostgreSQL) changeUserPassword(ctx context.Context, username string, ch
p.Lock()
defer p.Unlock()
db, err := p.getConnection(ctx)
var db *sql.DB
var err error
if selfManagedPass == "" {
db, err = p.getConnection(ctx)
if err != nil {
return fmt.Errorf("unable to get connection: %w", err)
}
} else {
db, err = p.getStaticConnection(ctx, username, selfManagedPass)
if err != nil {
return fmt.Errorf("unable to get static connection from cache: %w", err)
}
}
// Check if the role exists
var exists bool
@@ -285,7 +303,7 @@ func (p *PostgreSQL) changeUserPassword(ctx context.Context, username string, ch
return nil
}
func (p *PostgreSQL) changeUserExpiration(ctx context.Context, username string, changeExp *dbplugin.ChangeExpiration) error {
func (p *PostgreSQL) changeUserExpiration(ctx context.Context, username string, changeExp *dbplugin.ChangeExpiration, selfManagedPass string) error {
p.Lock()
defer p.Unlock()
@@ -294,9 +312,18 @@ func (p *PostgreSQL) changeUserExpiration(ctx context.Context, username string,
renewStmts = []string{defaultExpirationStatement}
}
db, err := p.getConnection(ctx)
var db *sql.DB
var err error
if selfManagedPass == "" {
db, err = p.getConnection(ctx)
if err != nil {
return err
return fmt.Errorf("unable to get connection: %w", err)
}
} else {
db, err = p.getStaticConnection(ctx, username, selfManagedPass)
if err != nil {
return fmt.Errorf("unable to get static connection from cache: %w", err)
}
}
tx, err := db.BeginTx(ctx, nil)

View File

@@ -640,6 +640,94 @@ func TestPostgreSQL_Initialize_CloudGCP(t *testing.T) {
}
}
// TestPostgreSQL_Initialize_SelfManaged_OSS tests the initialization of
// the self-managed flow and ensures an error is returned on OSS.
func TestPostgreSQL_Initialize_SelfManaged_OSS(t *testing.T) {
cleanup, url := postgresql.PrepareTestContainerSelfManaged(t)
defer cleanup()
connURL := fmt.Sprintf("postgresql://{{username}}:{{password}}@%s/postgres?sslmode=disable", url.Host)
testCases := []struct {
name string
connectionDetails map[string]interface{}
wantErr bool
errContains string
}{
{
name: "no parameters set",
connectionDetails: map[string]interface{}{
"connection_url": connURL,
"self_managed": false,
"username": "",
"password": "",
},
wantErr: true,
errContains: "must either provide username/password or set self-managed to 'true'",
},
{
name: "both sets of parameters set",
connectionDetails: map[string]interface{}{
"connection_url": connURL,
"self_managed": true,
"username": "test",
"password": "test",
},
wantErr: true,
errContains: "cannot use both self-managed and vault-managed workflows",
},
{
name: "either username/password with self-managed",
connectionDetails: map[string]interface{}{
"connection_url": connURL,
"self_managed": true,
"username": "test",
"password": "",
},
wantErr: true,
errContains: "cannot use both self-managed and vault-managed workflows",
},
{
name: "cache not implemented",
connectionDetails: map[string]interface{}{
"connection_url": connURL,
"self_managed": true,
"username": "",
"password": "",
},
wantErr: true,
errContains: "self-managed static roles only available in Vault Enterprise",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
req := dbplugin.InitializeRequest{
Config: tc.connectionDetails,
VerifyConnection: true,
}
db := new()
_, err := dbtesting.VerifyInitialize(t, db, req)
if err == nil && tc.wantErr {
t.Fatalf("got: %s, wantErr: %t", err, tc.wantErr)
}
if err != nil && !strings.Contains(err.Error(), tc.errContains) {
t.Fatalf("expected error: %s, received error: %s", tc.errContains, err)
}
if !tc.wantErr && !db.Initialized {
t.Fatal("Database should be initialized")
}
if err := db.Close(); err != nil {
t.Fatalf("err closing DB: %s", err)
}
})
}
}
// TestPostgreSQL_PasswordAuthentication tests that the default "password_authentication" is "none", and that
// an error is returned if an invalid "password_authentication" is provided.
func TestPostgreSQL_PasswordAuthentication(t *testing.T) {
@@ -1045,6 +1133,37 @@ func TestUpdateUser_Password(t *testing.T) {
})
}
// TestUpdateUser_SelfManaged_OSS checks basic validation
// for self-managed fields and confirms an error is returned on OSS
func TestUpdateUser_SelfManaged_OSS(t *testing.T) {
// Shared test container for speed - there should not be any overlap between the tests
db, cleanup := getPostgreSQL(t, nil)
defer cleanup()
updateReq := dbplugin.UpdateUserRequest{
Username: "static",
Password: &dbplugin.ChangePassword{
NewPassword: "somenewpassword",
Statements: dbplugin.Statements{
Commands: nil,
},
},
SelfManagedPassword: "test",
}
expectedErr := "self-managed static roles only available in Vault Enterprise"
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err := db.UpdateUser(ctx, updateReq)
if err == nil {
t.Fatalf("err expected, got nil")
}
if !strings.Contains(err.Error(), expectedErr) {
t.Fatalf("err expected: %s, got: %s", expectedErr, err)
}
}
func TestUpdateUser_Expiration(t *testing.T) {
type testCase struct {
initialExpiration time.Time

View File

@@ -116,6 +116,7 @@ func TestConversionsHaveAllFields(t *testing.T) {
},
},
},
SelfManagedPassword: "test-password",
}
protoReq, err := updateUserReqToProto(req)
@@ -194,6 +195,7 @@ func TestConversionsHaveAllFields(t *testing.T) {
},
},
},
SelfManagedPassword: "test-password",
}
protoReq, err := getUpdateUserRequest(req)

View File

@@ -181,6 +181,13 @@ type UpdateUserRequest struct {
// Expiration indicates the new expiration date to change to.
// If nil, no change is requested.
Expiration *ChangeExpiration
// SelfManagedPassword is the password for an externally managed user in the DB.
// If this field is supplied, a DB connection is retrieved from the static
// account cache for the particular DB plugin and used to update the password of
// the self-managed static role.
// *ENTERPRISE-ONLY*
SelfManagedPassword string
}
// ChangePublicKey of a given user

View File

@@ -204,6 +204,7 @@ func updateUserReqToProto(req UpdateUserRequest) (*proto.UpdateUserRequest, erro
Password: password,
PublicKey: publicKey,
Expiration: expiration,
SelfManagedPassword: req.SelfManagedPassword,
}
return rpcReq, nil
}

View File

@@ -227,6 +227,7 @@ func getUpdateUserRequest(req *proto.UpdateUserRequest) (UpdateUserRequest, erro
Password: password,
PublicKey: publicKey,
Expiration: expiration,
SelfManagedPassword: req.SelfManagedPassword,
}
if !hasChange(dbReq) {

View File

@@ -348,6 +348,7 @@ type UpdateUserRequest struct {
Expiration *ChangeExpiration `protobuf:"bytes,3,opt,name=expiration,proto3" json:"expiration,omitempty"`
PublicKey *ChangePublicKey `protobuf:"bytes,4,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
CredentialType int32 `protobuf:"varint,5,opt,name=credential_type,json=credentialType,proto3" json:"credential_type,omitempty"`
SelfManagedPassword string `protobuf:"bytes,6,opt,name=self_managed_password,json=selfManagedPassword,proto3" json:"self_managed_password,omitempty"`
}
func (x *UpdateUserRequest) Reset() {
@@ -417,6 +418,13 @@ func (x *UpdateUserRequest) GetCredentialType() int32 {
return 0
}
func (x *UpdateUserRequest) GetSelfManagedPassword() string {
if x != nil {
return x.SelfManagedPassword
}
return ""
}
type ChangePassword struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -910,7 +918,7 @@ var file_sdk_database_dbplugin_v5_proto_database_proto_rawDesc = []byte{
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22,
0x2d, 0x0a, 0x0f, 0x4e, 0x65, 0x77, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x8d,
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xc1,
0x02, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65,
@@ -927,76 +935,79 @@ var file_sdk_database_dbplugin_v5_proto_database_proto_rawDesc = []byte{
0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c,
0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74,
0x69, 0x61, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e,
0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x22, 0x6c,
0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x65, 0x77, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x77, 0x50, 0x61, 0x73, 0x73, 0x77,
0x6f, 0x72, 0x64, 0x12, 0x37, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74,
0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67,
0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73,
0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x70, 0x0a, 0x0f,
0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12,
0x24, 0x0a, 0x0e, 0x6e, 0x65, 0x77, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x6e, 0x65, 0x77, 0x50, 0x75, 0x62, 0x6c,
0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x37, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65,
0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x64, 0x62, 0x70, 0x6c,
0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
0x74, 0x73, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x8e,
0x01, 0x0a, 0x10, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x41, 0x0a, 0x0e, 0x6e, 0x65, 0x77, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x6e, 0x65, 0x77, 0x45, 0x78, 0x70, 0x69,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x37, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x64, 0x62, 0x70,
0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65,
0x6e, 0x74, 0x73, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22,
0x14, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x68, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55,
0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73,
0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73,
0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x37, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x64, 0x62, 0x70,
0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65,
0x6e, 0x74, 0x73, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22,
0x14, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x0a, 0x0c, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x22, 0x28, 0x0a, 0x0a, 0x53, 0x74, 0x61,
0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x6f, 0x6d, 0x6d, 0x61,
0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x43, 0x6f, 0x6d, 0x6d, 0x61,
0x6e, 0x64, 0x73, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x32, 0xa5, 0x03, 0x0a,
0x08, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0a, 0x49, 0x6e, 0x69,
0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x12, 0x1e, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67,
0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67,
0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x07, 0x4e, 0x65, 0x77, 0x55,
0x73, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76,
0x35, 0x2e, 0x4e, 0x65, 0x77, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x1c, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x4e,
0x65, 0x77, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d,
0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x64,
0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74,
0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x64,
0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74,
0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a,
0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x64, 0x62,
0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x64, 0x62,
0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x04,
0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e,
0x76, 0x35, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75,
0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x12, 0x12, 0x2e, 0x64,
0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79,
0x1a, 0x12, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x45,
0x6d, 0x70, 0x74, 0x79, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x76, 0x61, 0x75,
0x6c, 0x74, 0x2f, 0x73, 0x64, 0x6b, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2f,
0x64, 0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x76, 0x35, 0x2f, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x32,
0x0a, 0x15, 0x73, 0x65, 0x6c, 0x66, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x5f, 0x70,
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x73,
0x65, 0x6c, 0x66, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x22, 0x6c, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73,
0x77, 0x6f, 0x72, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x65, 0x77, 0x5f, 0x70, 0x61, 0x73, 0x73,
0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x77, 0x50,
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x37, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65,
0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x64, 0x62,
0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x73, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73,
0x22, 0x70, 0x0a, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,
0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x65, 0x77, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x6e, 0x65, 0x77,
0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x37, 0x0a, 0x0a, 0x73, 0x74, 0x61,
0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
0x64, 0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x53, 0x74, 0x61, 0x74,
0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
0x74, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x10, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x45, 0x78, 0x70,
0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x41, 0x0a, 0x0e, 0x6e, 0x65, 0x77, 0x5f, 0x65,
0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x6e, 0x65, 0x77,
0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x37, 0x0a, 0x0a, 0x73, 0x74,
0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17,
0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x53, 0x74, 0x61,
0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65,
0x6e, 0x74, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65,
0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x68, 0x0a, 0x11, 0x44, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a,
0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x37, 0x0a, 0x0a, 0x73, 0x74,
0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17,
0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x53, 0x74, 0x61,
0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65,
0x6e, 0x74, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65,
0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x0a, 0x0c, 0x54, 0x79, 0x70,
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x22, 0x28, 0x0a,
0x0a, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x43,
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x43,
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79,
0x32, 0xa5, 0x03, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x4d, 0x0a,
0x0a, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x12, 0x1e, 0x2e, 0x64, 0x62,
0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61,
0x6c, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x64, 0x62,
0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61,
0x6c, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x07,
0x4e, 0x65, 0x77, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67,
0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x4e, 0x65, 0x77, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e,
0x76, 0x35, 0x2e, 0x4e, 0x65, 0x77, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72,
0x12, 0x1e, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x55,
0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x1f, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x55,
0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x4d, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12,
0x1e, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x44, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x1f, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x44, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x35, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75,
0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19, 0x2e, 0x64,
0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x73, 0x65,
0x12, 0x12, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x35, 0x2e, 0x45,
0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e,
0x76, 0x35, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68,
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70,
0x2f, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2f, 0x73, 0x64, 0x6b, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62,
0x61, 0x73, 0x65, 0x2f, 0x64, 0x62, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x76, 0x35, 0x2f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@@ -53,6 +53,7 @@ message UpdateUserRequest {
ChangeExpiration expiration = 3;
ChangePublicKey public_key = 4;
int32 credential_type = 5;
string self_managed_password = 6;
}
message ChangePassword {

View File

@@ -0,0 +1,16 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
//go:build !enterprise
package cacheutil
import "errors"
type EvictionFunc func(key interface{}, value interface{})
type Cache struct{}
func NewCache(_ int, _ EvictionFunc) (*Cache, error) {
return nil, errors.New("self-managed static roles only available in Vault Enterprise")
}

View File

@@ -15,9 +15,11 @@ import (
"time"
"github.com/hashicorp/errwrap"
log "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/go-uuid"
"github.com/hashicorp/vault/sdk/database/dbplugin"
"github.com/hashicorp/vault/sdk/database/helper/cacheutil"
"github.com/hashicorp/vault/sdk/database/helper/dbutil"
"github.com/hashicorp/vault/sdk/helper/pluginutil"
"github.com/jackc/pgx/v4"
@@ -34,6 +36,12 @@ const (
const (
dbTypePostgres = "pgx"
cloudSQLPostgres = "cloudsql-postgres"
// controls the size of the static account cache
// as part of the self-managed workflow
defaultStaticCacheSize = 4
defaultSelfManagedUsername = "self-managed-user"
defaultSelfManagedPassword = "self-managed-password"
)
var _ ConnectionProducer = &SQLConnectionProducer{}
@@ -46,6 +54,7 @@ type SQLConnectionProducer struct {
MaxConnectionLifetimeRaw interface{} `json:"max_connection_lifetime" mapstructure:"max_connection_lifetime" structs:"max_connection_lifetime"`
DisableEscaping bool `json:"disable_escaping" mapstructure:"disable_escaping" structs:"disable_escaping"`
usePrivateIP bool `json:"use_private_ip" mapstructure:"use_private_ip" structs:"use_private_ip"`
SelfManaged bool `json:"self_managed" mapstructure:"self_managed" structs:"self_managed"`
// Username/Password is the default auth type when AuthType is not set
Username string `json:"username" mapstructure:"username" structs:"username"`
@@ -66,6 +75,7 @@ type SQLConnectionProducer struct {
maxConnectionLifetime time.Duration
Initialized bool
db *sql.DB
staticAccountsCache *cacheutil.Cache
sync.Mutex
}
@@ -89,6 +99,11 @@ func (c *SQLConnectionProducer) Init(ctx context.Context, conf map[string]interf
return nil, fmt.Errorf("connection_url cannot be empty")
}
isTemplatedURL := true
if !strings.Contains(c.ConnectionURL, "{{username}}") || !strings.Contains(c.ConnectionURL, "{{password}}") {
isTemplatedURL = false
}
// Do not allow the username or password template pattern to be used as
// part of the user-supplied username or password
if strings.Contains(c.Username, "{{username}}") ||
@@ -99,11 +114,28 @@ func (c *SQLConnectionProducer) Init(ctx context.Context, conf map[string]interf
return nil, fmt.Errorf("username and/or password cannot contain the template variables")
}
// validate that at least one of username/password / self_managed is set
if !c.SelfManaged && (c.Username == "" && c.Password == "") && isTemplatedURL {
return nil, fmt.Errorf("must either provide username/password or set self-managed to 'true'")
}
// validate that self-managed and username/password are mutually exclusive
if c.SelfManaged {
if (c.Username != "" || c.Password != "") || !isTemplatedURL {
return nil, fmt.Errorf("cannot use both self-managed and vault-managed workflows")
}
}
var username string
var password string
if !c.SelfManaged {
// Default behavior
username = c.Username
password = c.Password
// Don't escape special characters for MySQL password
// Also don't escape special characters for the username and password if
// the disable_escaping parameter is set to true
username := c.Username
password := c.Password
if !c.DisableEscaping {
username = url.PathEscape(c.Username)
}
@@ -111,6 +143,13 @@ func (c *SQLConnectionProducer) Init(ctx context.Context, conf map[string]interf
password = url.PathEscape(c.Password)
}
} else {
// this is added to make middleware happy
// these placeholders are replaced when we make the actual static connection
username = defaultSelfManagedUsername
password = defaultSelfManagedPassword
}
// QueryHelper doesn't do any SQL escaping, but if it starts to do so
// then maybe we won't be able to use it to do URL substitution any more.
c.ConnectionURL = dbutil.QueryHelper(c.ConnectionURL, map[string]string{
@@ -159,11 +198,35 @@ func (c *SQLConnectionProducer) Init(ctx context.Context, conf map[string]interf
c.cloudDialerCleanup = dialerCleanup
}
if c.SelfManaged && c.staticAccountsCache == nil {
logger := log.New(&log.LoggerOptions{
Level: log.Trace,
})
closer := func(key interface{}, value interface{}) {
logger.Trace(fmt.Sprintf("Evicting key %s from static LRU cache", key))
conn, ok := value.(*sql.DB)
if !ok {
logger.Error(fmt.Sprintf("error retrieving connection %s from static LRU cache, err=%s", key, err))
}
if err := conn.Close(); err != nil {
logger.Error(fmt.Sprintf("error closing connection for %s, err=%s", key, err))
}
logger.Trace(fmt.Sprintf("closed DB connection for %s", key))
}
c.staticAccountsCache, err = cacheutil.NewCache(defaultStaticCacheSize, closer)
if err != nil {
return nil, fmt.Errorf("error initializing static account cache: %s", err)
}
}
// Set initialized to true at this point since all fields are set,
// and the connection can be established at a later time.
c.Initialized = true
if verifyConnection {
// only verify if not self-managed
if verifyConnection && !c.SelfManaged {
if _, err := c.Connection(ctx); err != nil {
return nil, errwrap.Wrapf("error verifying connection: {{err}}", err)
}
@@ -210,22 +273,8 @@ func (c *SQLConnectionProducer) Connection(ctx context.Context) (interface{}, er
}
// Otherwise, attempt to make connection
conn := c.ConnectionURL
// PostgreSQL specific settings
if strings.HasPrefix(conn, "postgres://") || strings.HasPrefix(conn, "postgresql://") {
// Ensure timezone is set to UTC for all the connections
if strings.Contains(conn, "?") {
conn += "&timezone=UTC"
} else {
conn += "?timezone=UTC"
}
// Ensure a reasonable application_name is set
if !strings.Contains(conn, "application_name") {
conn += "&application_name=vault"
}
}
// Apply PostgreSQL specific settings if needed
conn := applyPostgresSettings(c.ConnectionURL)
if driverName == dbTypePostgres && c.TLSConfig != nil {
config, err := pgx.ParseConfig(conn)
@@ -312,6 +361,25 @@ func (c *SQLConnectionProducer) SetCredentials(ctx context.Context, statements d
return "", "", dbutil.Unimplemented()
}
func applyPostgresSettings(connURL string) string {
res := connURL
if strings.HasPrefix(res, "postgres://") || strings.HasPrefix(res, "postgresql://") {
// Ensure timezone is set to UTC for all the connections
if strings.Contains(res, "?") {
res += "&timezone=UTC"
} else {
res += "?timezone=UTC"
}
// Ensure a reasonable application_name is set
if !strings.Contains(res, "application_name") {
res += "&application_name=vault"
}
}
return res
}
var configurableAuthTypes = map[string]bool{
AuthTypeUsernamePassword: true,
AuthTypeCert: true,

View File

@@ -0,0 +1,16 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
//go:build !enterprise
package connutil
import (
"context"
"database/sql"
"errors"
)
func (c *SQLConnectionProducer) StaticConnection(_ context.Context, _, _ string) (*sql.DB, error) {
return nil, errors.New("self-managed static roles only available in Vault Enterprise")
}