mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-03 20:17:59 +00:00 
			
		
		
		
	backport of commit 30f19b383f (#23768)
				
					
				
			Co-authored-by: kpcraig <3031348+kpcraig@users.noreply.github.com>
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							635d2943fb
						
					
				
				
					commit
					ce0c6f9336
				
			@@ -212,6 +212,20 @@ func (b *backend) pathStaticRolesWrite(ctx context.Context, req *logical.Request
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, fmt.Errorf("failed to add item into the rotation queue for role %q: %w", config.Name, err)
 | 
								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{
 | 
						return &logical.Response{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -125,11 +125,20 @@ func TestStaticRolesWrite(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	cases := []struct {
 | 
						cases := []struct {
 | 
				
			||||||
		name string
 | 
							name string
 | 
				
			||||||
		opts          []awsutil.MockIAMOption
 | 
							// 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{}
 | 
							data          map[string]interface{}
 | 
				
			||||||
		expectedError bool
 | 
							expectedError bool
 | 
				
			||||||
		findUser      bool
 | 
							findUser      bool
 | 
				
			||||||
 | 
							// if data is sent the name "johnny", then we'll match an existing user with rotation period 24 hours.
 | 
				
			||||||
		isUpdate    bool
 | 
							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",
 | 
								name: "happy path",
 | 
				
			||||||
@@ -168,7 +177,7 @@ func TestStaticRolesWrite(t *testing.T) {
 | 
				
			|||||||
			expectedError: true,
 | 
								expectedError: true,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name: "update existing user",
 | 
								name: "update existing user, decreased rotation duration",
 | 
				
			||||||
			opts: []awsutil.MockIAMOption{
 | 
								opts: []awsutil.MockIAMOption{
 | 
				
			||||||
				awsutil.WithGetUserOutput(&iam.GetUserOutput{User: &iam.User{UserName: aws.String("john-doe"), UserId: aws.String("unique-id")}}),
 | 
									awsutil.WithGetUserOutput(&iam.GetUserOutput{User: &iam.User{UserName: aws.String("john-doe"), UserId: aws.String("unique-id")}}),
 | 
				
			||||||
				awsutil.WithListAccessKeysOutput(&iam.ListAccessKeysOutput{
 | 
									awsutil.WithListAccessKeysOutput(&iam.ListAccessKeysOutput{
 | 
				
			||||||
@@ -189,6 +198,31 @@ func TestStaticRolesWrite(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
			findUser:    true,
 | 
								findUser:    true,
 | 
				
			||||||
			isUpdate:    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
 | 
									expectedData = staticRole
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var actualItem *queue.Item
 | 
				
			||||||
 | 
								if c.isUpdate {
 | 
				
			||||||
 | 
									actualItem, _ = b.credRotationQueue.PopByKey(expectedData.Name)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if u, ok := fieldData.GetOk("username"); ok {
 | 
								if u, ok := fieldData.GetOk("username"); ok {
 | 
				
			||||||
				expectedData.Username = u.(string)
 | 
									expectedData.Username = u.(string)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -289,6 +328,20 @@ func TestStaticRolesWrite(t *testing.T) {
 | 
				
			|||||||
			if en, an := expectedData.Name, actualData.Name; en != an {
 | 
								if en, an := expectedData.Name, actualData.Name; en != an {
 | 
				
			||||||
				t.Fatalf("mismatched role name, expected %q, but got %q", 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
 | 
					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
 | 
					with an AWS IAM User, which will be adopted and managed by Vault, including rotating it according
 | 
				
			||||||
to the configured `rotation_period`.
 | 
					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
 | 
					- `rotation_period` `(string/int: <required>)` – Specifies the amount of time
 | 
				
			||||||
Vault should wait before rotating the password. The minimum is 1 minute. Can be
 | 
					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)).
 | 
					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
 | 
					### Sample payload
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user