mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 17:52:32 +00:00
VAULT-18307: update rotation period for aws static roles on update (#23528)
This commit is contained in:
@@ -212,6 +212,20 @@ func (b *backend) pathStaticRolesWrite(ctx context.Context, req *logical.Request
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add item into the rotation queue for role %q: %w", config.Name, err)
|
||||
}
|
||||
} else {
|
||||
// creds already exist, so all we need to do is update the rotation
|
||||
// what here stays the same and what changes? Can we change the name?
|
||||
i, err := b.credRotationQueue.PopByKey(config.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("expected an item with name %q, but got an error: %w", config.Name, err)
|
||||
}
|
||||
i.Value = config
|
||||
// update the next rotation to occur at now + the new rotation period
|
||||
i.Priority = time.Now().Add(config.RotationPeriod).Unix()
|
||||
err = b.credRotationQueue.Push(i)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add updated item into the rotation queue for role %q: %w", config.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return &logical.Response{
|
||||
|
||||
@@ -124,12 +124,21 @@ func TestStaticRolesWrite(t *testing.T) {
|
||||
bgCTX := context.Background()
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
opts []awsutil.MockIAMOption
|
||||
name string
|
||||
// objects to return from mock IAM.
|
||||
// You'll need a GetUserOutput (to validate the existence of the user being written,
|
||||
// the keys the user has already been assigned,
|
||||
// and the new key vault requests.
|
||||
opts []awsutil.MockIAMOption // objects to return from the mock IAM
|
||||
// the name, username if updating, and rotation_period of the user. This is the inbound request the cod would get.
|
||||
data map[string]interface{}
|
||||
expectedError bool
|
||||
findUser bool
|
||||
isUpdate bool
|
||||
// if data is sent the name "johnny", then we'll match an existing user with rotation period 24 hours.
|
||||
isUpdate bool
|
||||
newPriority int64 // update time of new item in queue, skip if isUpdate false. There is a wiggle room of 5 seconds
|
||||
// so the deltas between the old and the new update time should be larger than that to ensure the difference
|
||||
// can be detected.
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
@@ -168,7 +177,7 @@ func TestStaticRolesWrite(t *testing.T) {
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "update existing user",
|
||||
name: "update existing user, decreased rotation duration",
|
||||
opts: []awsutil.MockIAMOption{
|
||||
awsutil.WithGetUserOutput(&iam.GetUserOutput{User: &iam.User{UserName: aws.String("john-doe"), UserId: aws.String("unique-id")}}),
|
||||
awsutil.WithListAccessKeysOutput(&iam.ListAccessKeysOutput{
|
||||
@@ -187,8 +196,33 @@ func TestStaticRolesWrite(t *testing.T) {
|
||||
"name": "johnny",
|
||||
"rotation_period": "19m",
|
||||
},
|
||||
findUser: true,
|
||||
isUpdate: true,
|
||||
findUser: true,
|
||||
isUpdate: true,
|
||||
newPriority: time.Now().Add(19 * time.Minute).Unix(),
|
||||
},
|
||||
{
|
||||
name: "update existing user, increased rotation duration",
|
||||
opts: []awsutil.MockIAMOption{
|
||||
awsutil.WithGetUserOutput(&iam.GetUserOutput{User: &iam.User{UserName: aws.String("john-doe"), UserId: aws.String("unique-id")}}),
|
||||
awsutil.WithListAccessKeysOutput(&iam.ListAccessKeysOutput{
|
||||
AccessKeyMetadata: []*iam.AccessKeyMetadata{},
|
||||
IsTruncated: aws.Bool(false),
|
||||
}),
|
||||
awsutil.WithCreateAccessKeyOutput(&iam.CreateAccessKeyOutput{
|
||||
AccessKey: &iam.AccessKey{
|
||||
AccessKeyId: aws.String("abcdefghijklmnopqrstuvwxyz"),
|
||||
SecretAccessKey: aws.String("zyxwvutsrqponmlkjihgfedcba"),
|
||||
UserName: aws.String("john-doe"),
|
||||
},
|
||||
}),
|
||||
},
|
||||
data: map[string]interface{}{
|
||||
"name": "johnny",
|
||||
"rotation_period": "40h",
|
||||
},
|
||||
findUser: true,
|
||||
isUpdate: true,
|
||||
newPriority: time.Now().Add(40 * time.Hour).Unix(),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -269,6 +303,11 @@ func TestStaticRolesWrite(t *testing.T) {
|
||||
expectedData = staticRole
|
||||
}
|
||||
|
||||
var actualItem *queue.Item
|
||||
if c.isUpdate {
|
||||
actualItem, _ = b.credRotationQueue.PopByKey(expectedData.Name)
|
||||
}
|
||||
|
||||
if u, ok := fieldData.GetOk("username"); ok {
|
||||
expectedData.Username = u.(string)
|
||||
}
|
||||
@@ -289,6 +328,20 @@ func TestStaticRolesWrite(t *testing.T) {
|
||||
if en, an := expectedData.Name, actualData.Name; en != an {
|
||||
t.Fatalf("mismatched role name, expected %q, but got %q", en, an)
|
||||
}
|
||||
|
||||
// one-off to avoid importing/casting
|
||||
abs := func(x int64) int64 {
|
||||
if x < 0 {
|
||||
return -x
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
if c.isUpdate {
|
||||
if ep, ap := c.newPriority, actualItem.Priority; abs(ep-ap) > 5 { // 5 second wiggle room for how long the test takes
|
||||
t.Fatalf("mismatched updated priority, expected %d but got %d", ep, ap)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
3
changelog/23528.txt
Normal file
3
changelog/23528.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
```release-note:bug
|
||||
secrets/aws: update credential rotation deadline when static role rotation period is updated
|
||||
```
|
||||
@@ -586,7 +586,7 @@ $ curl \
|
||||
}
|
||||
```
|
||||
|
||||
## Create static role
|
||||
## Create/Update static role
|
||||
This endpoint creates or updates static role definitions. A static role is a 1-to-1 mapping
|
||||
with an AWS IAM User, which will be adopted and managed by Vault, including rotating it according
|
||||
to the configured `rotation_period`.
|
||||
@@ -613,6 +613,7 @@ is specified as part of the URL.
|
||||
- `rotation_period` `(string/int: <required>)` – Specifies the amount of time
|
||||
Vault should wait before rotating the password. The minimum is 1 minute. Can be
|
||||
specified in either `24h` or `86400` format (see [duration format strings](/vault/docs/concepts/duration-format)).
|
||||
Updating the rotation period will 'reset' the next rotation to occur at `now` + `rotation_period`.
|
||||
|
||||
### Sample payload
|
||||
|
||||
|
||||
Reference in New Issue
Block a user