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

fix(secretsmanager): automatic rotation cannot be disabled #18906

Merged
merged 11 commits into from
May 17, 2022
18 changes: 15 additions & 3 deletions packages/@aws-cdk/aws-secretsmanager/lib/rotation-schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export interface RotationScheduleOptions {
* Specifies the number of days after the previous rotation before
* Secrets Manager triggers the next automatic rotation.
*
* A value of zero will disable automatic rotation - `Duration.days(0)`.
*
* @default Duration.days(30)
*/
readonly automaticallyAfter?: Duration;
Expand Down Expand Up @@ -105,13 +107,23 @@ export class RotationSchedule extends Resource {
);
}

let automaticallyAfterDays: number | undefined = undefined;
if (props.automaticallyAfter?.toMilliseconds() !== 0) {
automaticallyAfterDays = props.automaticallyAfter?.toDays() || 30;
}

let rotationRules: CfnRotationSchedule.RotationRulesProperty | undefined = undefined;
if (automaticallyAfterDays !== undefined) {
rotationRules = {
automaticallyAfterDays,
};
}

new CfnRotationSchedule(this, 'Resource', {
secretId: props.secret.secretArn,
rotationLambdaArn: props.rotationLambda?.functionArn,
hostedRotationLambda: props.hostedRotation?.bind(props.secret, this),
rotationRules: {
automaticallyAfterDays: props.automaticallyAfter && props.automaticallyAfter.toDays() || 30,
},
rotationRules,
});

// Prevent secrets deletions when rotation is in place
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as ec2 from '@aws-cdk/aws-ec2';
import * as kms from '@aws-cdk/aws-kms';
import * as lambda from '@aws-cdk/aws-lambda';
import * as cdk from '@aws-cdk/core';
import { Duration } from '@aws-cdk/core';
import * as secretsmanager from '../lib';

let stack: cdk.Stack;
Expand Down Expand Up @@ -514,3 +515,42 @@ describe('hosted rotation', () => {
.toThrow(/Cannot use connections for a hosted rotation that is not deployed in a VPC/);
});
});

describe('manual rotations', () => {
test('automaticallyAfter with any duration of zero leaves RotationRules unset', () => {
const checkRotationNotSet = (automaticallyAfter: Duration) => {
// GIVEN
const localStack = new cdk.Stack();
const secret = new secretsmanager.Secret(localStack, 'Secret');
const rotationLambda = new lambda.Function(localStack, 'Lambda', {
runtime: lambda.Runtime.NODEJS_10_X,
code: lambda.Code.fromInline('export.handler = event => event;'),
handler: 'index.handler',
});

// WHEN
new secretsmanager.RotationSchedule(localStack, 'RotationSchedule', {
secret,
rotationLambda,
automaticallyAfter,
});

// THEN
Template.fromStack(localStack).hasResourceProperties('AWS::SecretsManager::RotationSchedule', Match.objectEquals({
SecretId: { Ref: 'SecretA720EF05' },
RotationLambdaARN: {
'Fn::GetAtt': [
'LambdaD247545B',
'Arn',
],
},
}));
};

checkRotationNotSet(Duration.days(0));
checkRotationNotSet(Duration.hours(0));
checkRotationNotSet(Duration.minutes(0));
checkRotationNotSet(Duration.seconds(0));
checkRotationNotSet(Duration.millis(0));
});
});