Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for db schedule-based static role rotations #367

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions api/v1beta1/vaultdynamicsecret_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ type VaultStaticCredsMetaData struct {
// "time to live". This value is compared to the LastVaultRotation to
// determine if a password needs to be rotated
RotationPeriod int64 `json:"rotationPeriod"`
// RotationSchedule is a "chron style" string representing the allowed
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// RotationSchedule is a "chron style" string representing the allowed
// RotationSchedule is a "cron style" string representing the allowed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ha, woops!

// schedule for each rotation.
// e.g. "1 0 * * *" would rotate at one minute past midnight (00:01) every
// day.
RotationSchedule string `json:"rotationSchedule"`
// TTL is the seconds remaining before the next rotation.
TTL int64 `json:"ttl"`
}
Expand Down
6 changes: 6 additions & 0 deletions chart/crds/secrets.hashicorp.com_vaultdynamicsecrets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,19 @@ spec:
be rotated
format: int64
type: integer
rotationSchedule:
description: RotationSchedule is a "chron style" string representing
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
description: RotationSchedule is a "chron style" string representing
description: RotationSchedule is a "cron style" string representing

the allowed schedule for each rotation. e.g. "1 0 * * *" would
rotate at one minute past midnight (00:01) every day.
type: string
ttl:
description: TTL is the seconds remaining before the next rotation.
format: int64
type: integer
required:
- lastVaultRotation
- rotationPeriod
- rotationSchedule
- ttl
type: object
required:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,19 @@ spec:
be rotated
format: int64
type: integer
rotationSchedule:
description: RotationSchedule is a "chron style" string representing
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
description: RotationSchedule is a "chron style" string representing
description: RotationSchedule is a "cron style" string representing

the allowed schedule for each rotation. e.g. "1 0 * * *" would
rotate at one minute past midnight (00:01) every day.
type: string
ttl:
description: TTL is the seconds remaining before the next rotation.
format: int64
type: integer
required:
- lastVaultRotation
- rotationPeriod
- rotationSchedule
- ttl
type: object
required:
Expand Down
7 changes: 6 additions & 1 deletion controllers/vaultdynamicsecret_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ func (r *VaultDynamicSecretReconciler) isRenewableLease(secretLease *secretsv1be
func (r *VaultDynamicSecretReconciler) isStaticCreds(meta *secretsv1beta1.VaultStaticCredsMetaData) bool {
// the ldap and database engines have minimum rotation period of 5s, requiring a
// minimum of 1s should be okay here.
return meta.LastVaultRotation > 0 && meta.RotationPeriod > 1
return meta.LastVaultRotation > 0 && (meta.RotationPeriod > 1 || meta.RotationSchedule != "")
}

func (r *VaultDynamicSecretReconciler) syncSecret(ctx context.Context, c vault.ClientBase, o *secretsv1beta1.VaultDynamicSecret) (*secretsv1beta1.VaultSecretLease, bool, error) {
Expand Down Expand Up @@ -332,6 +332,11 @@ func (r *VaultDynamicSecretReconciler) syncSecret(ctx context.Context, c vault.C
}
}
}
if v, ok := respData["rotation_schedule"]; ok && v != nil {
if schedule, ok := v.(string); ok && v != nil {
o.Status.StaticCredsMetaData.RotationSchedule = schedule
}
}
if v, ok := respData["ttl"]; ok && v != nil {
switch t := v.(type) {
case json.Number:
Expand Down
1 change: 1 addition & 0 deletions docs/api/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ _Appears in:_
| --- | --- |
| `lastVaultRotation` _integer_ | LastVaultRotation represents the last time Vault rotated the password |
| `rotationPeriod` _integer_ | RotationPeriod is number in seconds between each rotation, effectively a "time to live". This value is compared to the LastVaultRotation to determine if a password needs to be rotated |
| `rotationSchedule` _string_ | RotationSchedule is a "chron style" string representing the allowed schedule for each rotation. e.g. "1 0 * * *" would rotate at one minute past midnight (00:01) every day. |
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| `rotationSchedule` _string_ | RotationSchedule is a "chron style" string representing the allowed schedule for each rotation. e.g. "1 0 * * *" would rotate at one minute past midnight (00:01) every day. |
| `rotationSchedule` _string_ | RotationSchedule is a "cron style" string representing the allowed schedule for each rotation. e.g. "1 0 * * *" would rotate at one minute past midnight (00:01) every day. |

| `ttl` _integer_ | TTL is the seconds remaining before the next rotation. |


Expand Down
2 changes: 1 addition & 1 deletion test/integration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ type dynamicK8SOutputs struct {
}

func assertDynamicSecret(t *testing.T, client ctrlclient.Client, maxRetries int,
delay time.Duration, vdsObj *secretsv1beta1.VaultDynamicSecret, expected map[string]int,
delay time.Duration, vdsObj *secretsv1beta1.VaultDynamicSecret, expected map[string]interface{},
) {
t.Helper()

Expand Down
45 changes: 38 additions & 7 deletions test/integration/vaultdynamicsecret_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ func TestVaultDynamicSecret(t *testing.T) {
tests := []struct {
name string
authObj *secretsv1beta1.VaultAuth
expected map[string]int
expectedStatic map[string]int
expected map[string]interface{}
expectedStatic map[string]interface{}
create int
createStatic int
existing []string
Expand All @@ -199,7 +199,7 @@ func TestVaultDynamicSecret(t *testing.T) {
name: "existing-only",
existing: outputs.K8sDBSecrets,
authObj: auths[0],
expected: map[string]int{
expected: map[string]interface{}{
helpers.SecretDataKeyRaw: 100,
"username": 51,
"password": 20,
Expand All @@ -209,7 +209,7 @@ func TestVaultDynamicSecret(t *testing.T) {
name: "create-only",
create: 5,
authObj: auths[0],
expected: map[string]int{
expected: map[string]interface{}{
helpers.SecretDataKeyRaw: 100,
"username": 51,
"password": 20,
Expand All @@ -221,12 +221,12 @@ func TestVaultDynamicSecret(t *testing.T) {
createStatic: 5,
existing: outputs.K8sDBSecrets,
authObj: auths[0],
expected: map[string]int{
expected: map[string]interface{}{
helpers.SecretDataKeyRaw: 100,
"username": 51,
"password": 20,
},
expectedStatic: map[string]int{
expectedStatic: map[string]interface{}{
// the _raw, last_vault_rotation, and ttl keys are only tested for their presence in
// assertDynamicSecret, so no need to include them here.
"password": 20,
Expand All @@ -238,14 +238,45 @@ func TestVaultDynamicSecret(t *testing.T) {
name: "create-static",
createStatic: 5,
authObj: auths[0],
expectedStatic: map[string]int{
expectedStatic: map[string]interface{}{
// the _raw, last_vault_rotation, and ttl keys are only tested for their presence in
// assertDynamicSecret, so no need to include them here.
"password": 20,
"rotation_period": 2,
"username": 24,
},
},
{
name: "mixed-rotation-schedule",
create: 5,
createStatic: 5,
existing: outputs.K8sDBSecrets,
authObj: auths[0],
expected: map[string]interface{}{
helpers.SecretDataKeyRaw: 100,
"username": 51,
"password": 20,
},
expectedStatic: map[string]interface{}{
// the _raw, last_vault_rotation, and ttl keys are only tested for their presence in
// assertDynamicSecret, so no need to include them here.
"password": 20,
"rotation_schedule": "0 0 * * SAT",
"username": 24,
},
},
{
name: "create-static-rotation-schedule",
createStatic: 5,
authObj: auths[0],
expectedStatic: map[string]interface{}{
// the _raw, last_vault_rotation, and ttl keys are only tested for their presence in
// assertDynamicSecret, so no need to include them here.
"password": 20,
"rotation_schedule": "0 0 * * SAT",
"username": 24,
},
},
}

for _, tt := range tests {
Expand Down
Loading