mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 03:27:54 +00:00
Update DB Static role rotation logic to generate new password if retried password fails (#28989)
This commit is contained in:
@@ -1087,6 +1087,76 @@ func TestBackend_StaticRole_Role_name_check(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestStaticRole_NewCredentialGeneration verifies that new
|
||||||
|
// credentials are generated if a retried credential continues
|
||||||
|
// to fail
|
||||||
|
func TestStaticRole_NewCredentialGeneration(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
b, storage, mockDB := getBackend(t)
|
||||||
|
defer b.Cleanup(ctx)
|
||||||
|
configureDBMount(t, storage)
|
||||||
|
|
||||||
|
roleName := "hashicorp"
|
||||||
|
createRole(t, b, storage, mockDB, "hashicorp")
|
||||||
|
|
||||||
|
t.Run("rotation failures should generate new password on retry", func(t *testing.T) {
|
||||||
|
// Fail to rotate the role
|
||||||
|
generateWALFromFailedRotation(t, b, storage, mockDB, roleName)
|
||||||
|
|
||||||
|
// Get WAL
|
||||||
|
walIDs := requireWALs(t, storage, 1)
|
||||||
|
wal, err := b.findStaticWAL(ctx, storage, walIDs[0])
|
||||||
|
if err != nil || wal == nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store password
|
||||||
|
initialPassword := wal.NewPassword
|
||||||
|
|
||||||
|
// Rotate role manually and fail again #1 with same password
|
||||||
|
generateWALFromFailedRotation(t, b, storage, mockDB, roleName)
|
||||||
|
|
||||||
|
// Ensure WAL is deleted since retrying password failed
|
||||||
|
requireWALs(t, storage, 0)
|
||||||
|
|
||||||
|
// Successfully rotate the role
|
||||||
|
mockDB.On("UpdateUser", mock.Anything, mock.Anything).
|
||||||
|
Return(v5.UpdateUserResponse{}, nil).
|
||||||
|
Once()
|
||||||
|
_, err = b.HandleRequest(context.Background(), &logical.Request{
|
||||||
|
Operation: logical.UpdateOperation,
|
||||||
|
Path: "rotate-role/" + roleName,
|
||||||
|
Storage: storage,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure WAL is flushed since request was successful
|
||||||
|
requireWALs(t, storage, 0)
|
||||||
|
|
||||||
|
// Read the credential
|
||||||
|
data := map[string]interface{}{}
|
||||||
|
req := &logical.Request{
|
||||||
|
Operation: logical.ReadOperation,
|
||||||
|
Path: "static-creds/" + roleName,
|
||||||
|
Storage: storage,
|
||||||
|
Data: data,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := b.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirm successful rotation used new credential
|
||||||
|
// Assert previous failing credential is not being used
|
||||||
|
if resp.Data["password"] == initialPassword {
|
||||||
|
t.Fatalf("expected password to be different after second retry")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestWALsStillTrackedAfterUpdate(t *testing.T) {
|
func TestWALsStillTrackedAfterUpdate(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
b, storage, mockDB := getBackend(t)
|
b, storage, mockDB := getBackend(t)
|
||||||
|
|||||||
@@ -421,6 +421,7 @@ func (b *databaseBackend) setStaticAccount(ctx context.Context, s logical.Storag
|
|||||||
// Use credential from input if available. This happens if we're restoring from
|
// 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
|
// a WAL item or processing the rotation queue with an item that has a WAL
|
||||||
// associated with it
|
// associated with it
|
||||||
|
var usedCredentialFromPreviousRotation bool
|
||||||
if output.WALID != "" {
|
if output.WALID != "" {
|
||||||
wal, err := b.findStaticWAL(ctx, s, output.WALID)
|
wal, err := b.findStaticWAL(ctx, s, output.WALID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -448,6 +449,7 @@ func (b *databaseBackend) setStaticAccount(ctx context.Context, s logical.Storag
|
|||||||
Statements: statements,
|
Statements: statements,
|
||||||
}
|
}
|
||||||
input.Role.StaticAccount.Password = wal.NewPassword
|
input.Role.StaticAccount.Password = wal.NewPassword
|
||||||
|
usedCredentialFromPreviousRotation = true
|
||||||
case wal.CredentialType == v5.CredentialTypeRSAPrivateKey:
|
case wal.CredentialType == v5.CredentialTypeRSAPrivateKey:
|
||||||
// Roll forward by using the credential in the existing WAL entry
|
// Roll forward by using the credential in the existing WAL entry
|
||||||
updateReq.CredentialType = v5.CredentialTypeRSAPrivateKey
|
updateReq.CredentialType = v5.CredentialTypeRSAPrivateKey
|
||||||
@@ -456,6 +458,7 @@ func (b *databaseBackend) setStaticAccount(ctx context.Context, s logical.Storag
|
|||||||
Statements: statements,
|
Statements: statements,
|
||||||
}
|
}
|
||||||
input.Role.StaticAccount.PrivateKey = wal.NewPrivateKey
|
input.Role.StaticAccount.PrivateKey = wal.NewPrivateKey
|
||||||
|
usedCredentialFromPreviousRotation = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,6 +533,15 @@ func (b *databaseBackend) setStaticAccount(ctx context.Context, s logical.Storag
|
|||||||
_, err = dbi.database.UpdateUser(ctx, updateReq, false)
|
_, err = dbi.database.UpdateUser(ctx, updateReq, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.CloseIfShutdown(dbi, err)
|
b.CloseIfShutdown(dbi, err)
|
||||||
|
if usedCredentialFromPreviousRotation {
|
||||||
|
b.Logger().Debug("credential stored in WAL failed, deleting WAL", "role", input.RoleName, "WAL ID", output.WALID)
|
||||||
|
if err := framework.DeleteWAL(ctx, s, output.WALID); err != nil {
|
||||||
|
b.Logger().Warn("failed to delete WAL", "error", err, "WAL ID", output.WALID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a new WAL entry and credential for next attempt
|
||||||
|
output.WALID = ""
|
||||||
|
}
|
||||||
return output, fmt.Errorf("error setting credentials: %w", err)
|
return output, fmt.Errorf("error setting credentials: %w", err)
|
||||||
}
|
}
|
||||||
modified = true
|
modified = true
|
||||||
|
|||||||
3
changelog/28989.txt
Normal file
3
changelog/28989.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
```release-note:bug
|
||||||
|
secret/db: Update static role rotation to generate a new password after 2 failed attempts.
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user