mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +00:00 
			
		
		
		
	 a69ee0f65a
			
		
	
	a69ee0f65a
	
	
	
		
			
			This is part 1 of 4 for renaming the `newdbplugin` package. This copies the existing package to the new location but keeps the current one in place so we can migrate the existing references over more easily.
		
			
				
	
	
		
			213 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			213 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package database
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"time"
 | |
| 
 | |
| 	v5 "github.com/hashicorp/vault/sdk/database/dbplugin/v5"
 | |
| 	"github.com/hashicorp/vault/sdk/framework"
 | |
| 	"github.com/hashicorp/vault/sdk/logical"
 | |
| 	"github.com/hashicorp/vault/sdk/queue"
 | |
| )
 | |
| 
 | |
| func pathRotateRootCredentials(b *databaseBackend) []*framework.Path {
 | |
| 	return []*framework.Path{
 | |
| 		&framework.Path{
 | |
| 			Pattern: "rotate-root/" + framework.GenericNameRegex("name"),
 | |
| 			Fields: map[string]*framework.FieldSchema{
 | |
| 				"name": &framework.FieldSchema{
 | |
| 					Type:        framework.TypeString,
 | |
| 					Description: "Name of this database connection",
 | |
| 				},
 | |
| 			},
 | |
| 
 | |
| 			Operations: map[logical.Operation]framework.OperationHandler{
 | |
| 				logical.UpdateOperation: &framework.PathOperation{
 | |
| 					Callback:                    b.pathRotateRootCredentialsUpdate(),
 | |
| 					ForwardPerformanceSecondary: true,
 | |
| 					ForwardPerformanceStandby:   true,
 | |
| 				},
 | |
| 			},
 | |
| 
 | |
| 			HelpSynopsis:    pathCredsCreateReadHelpSyn,
 | |
| 			HelpDescription: pathCredsCreateReadHelpDesc,
 | |
| 		},
 | |
| 		&framework.Path{
 | |
| 			Pattern: "rotate-role/" + framework.GenericNameRegex("name"),
 | |
| 			Fields: map[string]*framework.FieldSchema{
 | |
| 				"name": &framework.FieldSchema{
 | |
| 					Type:        framework.TypeString,
 | |
| 					Description: "Name of the static role",
 | |
| 				},
 | |
| 			},
 | |
| 
 | |
| 			Operations: map[logical.Operation]framework.OperationHandler{
 | |
| 				logical.UpdateOperation: &framework.PathOperation{
 | |
| 					Callback:                    b.pathRotateRoleCredentialsUpdate(),
 | |
| 					ForwardPerformanceStandby:   true,
 | |
| 					ForwardPerformanceSecondary: true,
 | |
| 				},
 | |
| 			},
 | |
| 
 | |
| 			HelpSynopsis:    pathCredsCreateReadHelpSyn,
 | |
| 			HelpDescription: pathCredsCreateReadHelpDesc,
 | |
| 		},
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (b *databaseBackend) pathRotateRootCredentialsUpdate() framework.OperationFunc {
 | |
| 	return func(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
 | |
| 		name := data.Get("name").(string)
 | |
| 		if name == "" {
 | |
| 			return logical.ErrorResponse(respErrEmptyName), nil
 | |
| 		}
 | |
| 
 | |
| 		config, err := b.DatabaseConfig(ctx, req.Storage, name)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		dbi, err := b.GetConnection(ctx, req.Storage, name)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		defer func() {
 | |
| 			// Close the plugin
 | |
| 			dbi.closed = true
 | |
| 			if err := dbi.database.Close(); err != nil {
 | |
| 				b.Logger().Error("error closing the database plugin connection", "err", err)
 | |
| 			}
 | |
| 			// Even on error, still remove the connection
 | |
| 			delete(b.connections, name)
 | |
| 		}()
 | |
| 
 | |
| 		// Take out the backend lock since we are swapping out the connection
 | |
| 		b.Lock()
 | |
| 		defer b.Unlock()
 | |
| 
 | |
| 		// Take the write lock on the instance
 | |
| 		dbi.Lock()
 | |
| 		defer dbi.Unlock()
 | |
| 
 | |
| 		// Generate new credentials
 | |
| 		username := config.ConnectionDetails["username"].(string)
 | |
| 		oldPassword := config.ConnectionDetails["password"].(string)
 | |
| 		newPassword, err := dbi.database.GeneratePassword(ctx, b.System(), config.PasswordPolicy)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		config.ConnectionDetails["password"] = newPassword
 | |
| 
 | |
| 		// Write a WAL entry
 | |
| 		walID, err := framework.PutWAL(ctx, req.Storage, rotateRootWALKey, &rotateRootCredentialsWAL{
 | |
| 			ConnectionName: name,
 | |
| 			UserName:       username,
 | |
| 			OldPassword:    oldPassword,
 | |
| 			NewPassword:    newPassword,
 | |
| 		})
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		updateReq := v5.UpdateUserRequest{
 | |
| 			Username: username,
 | |
| 			Password: &v5.ChangePassword{
 | |
| 				NewPassword: newPassword,
 | |
| 				Statements: v5.Statements{
 | |
| 					Commands: config.RootCredentialsRotateStatements,
 | |
| 				},
 | |
| 			},
 | |
| 		}
 | |
| 		newConfigDetails, err := dbi.database.UpdateUser(ctx, updateReq, true)
 | |
| 		if err != nil {
 | |
| 			return nil, fmt.Errorf("failed to update user: %w", err)
 | |
| 		}
 | |
| 		if newConfigDetails != nil {
 | |
| 			config.ConnectionDetails = newConfigDetails
 | |
| 		}
 | |
| 
 | |
| 		err = storeConfig(ctx, req.Storage, name, config)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		err = framework.DeleteWAL(ctx, req.Storage, walID)
 | |
| 		if err != nil {
 | |
| 			b.Logger().Warn("unable to delete WAL", "error", err, "WAL ID", walID)
 | |
| 		}
 | |
| 		return nil, nil
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (b *databaseBackend) pathRotateRoleCredentialsUpdate() framework.OperationFunc {
 | |
| 	return func(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
 | |
| 		name := data.Get("name").(string)
 | |
| 		if name == "" {
 | |
| 			return logical.ErrorResponse("empty role name attribute given"), nil
 | |
| 		}
 | |
| 
 | |
| 		role, err := b.StaticRole(ctx, req.Storage, name)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		if role == nil {
 | |
| 			return logical.ErrorResponse("no static role found for role name"), nil
 | |
| 		}
 | |
| 
 | |
| 		// In create/update of static accounts, we only care if the operation
 | |
| 		// err'd , and this call does not return credentials
 | |
| 		item, err := b.popFromRotationQueueByKey(name)
 | |
| 		if err != nil {
 | |
| 			item = &queue.Item{
 | |
| 				Key: name,
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		resp, err := b.setStaticAccount(ctx, req.Storage, &setStaticAccountInput{
 | |
| 			RoleName: name,
 | |
| 			Role:     role,
 | |
| 		})
 | |
| 		// if err is not nil, we need to attempt to update the priority and place
 | |
| 		// this item back on the queue. The err should still be returned at the end
 | |
| 		// of this method.
 | |
| 		if err != nil {
 | |
| 			b.logger.Warn("unable to rotate credentials in rotate-role", "error", err)
 | |
| 			// Update the priority to re-try this rotation and re-add the item to
 | |
| 			// the queue
 | |
| 			item.Priority = time.Now().Add(10 * time.Second).Unix()
 | |
| 
 | |
| 			// Preserve the WALID if it was returned
 | |
| 			if resp != nil && resp.WALID != "" {
 | |
| 				item.Value = resp.WALID
 | |
| 			}
 | |
| 		} else {
 | |
| 			item.Priority = resp.RotationTime.Add(role.StaticAccount.RotationPeriod).Unix()
 | |
| 		}
 | |
| 
 | |
| 		// Add their rotation to the queue
 | |
| 		if err := b.pushItem(item); err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		// return any err from the setStaticAccount call
 | |
| 		return nil, err
 | |
| 	}
 | |
| }
 | |
| 
 | |
| const pathRotateCredentialsUpdateHelpSyn = `
 | |
| Request to rotate the root credentials for a certain database connection.
 | |
| `
 | |
| 
 | |
| const pathRotateCredentialsUpdateHelpDesc = `
 | |
| This path attempts to rotate the root credentials for the given database. 
 | |
| `
 | |
| 
 | |
| const pathRotateRoleCredentialsUpdateHelpSyn = `
 | |
| Request to rotate the credentials for a static user account.
 | |
| `
 | |
| const pathRotateRoleCredentialsUpdateHelpDesc = `
 | |
| This path attempts to rotate the credentials for the given static user account.
 | |
| `
 |