Skip to content

Commit c50d60c

Browse files
authored
fix(secretsmanager): automatic rotation cannot be disabled (#18906)
fixes #18749 Adds a `manualRotation` prop to `RotationSchedule` in order to leave `automaticallyAfterDays` unset on the underlying Cfn resource. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 10d13e4 commit c50d60c

File tree

2 files changed

+55
-3
lines changed

2 files changed

+55
-3
lines changed

Diff for: packages/@aws-cdk/aws-secretsmanager/lib/rotation-schedule.ts

+15-3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ export interface RotationScheduleOptions {
2929
* Specifies the number of days after the previous rotation before
3030
* Secrets Manager triggers the next automatic rotation.
3131
*
32+
* A value of zero will disable automatic rotation - `Duration.days(0)`.
33+
*
3234
* @default Duration.days(30)
3335
*/
3436
readonly automaticallyAfter?: Duration;
@@ -105,13 +107,23 @@ export class RotationSchedule extends Resource {
105107
);
106108
}
107109

110+
let automaticallyAfterDays: number | undefined = undefined;
111+
if (props.automaticallyAfter?.toMilliseconds() !== 0) {
112+
automaticallyAfterDays = props.automaticallyAfter?.toDays() || 30;
113+
}
114+
115+
let rotationRules: CfnRotationSchedule.RotationRulesProperty | undefined = undefined;
116+
if (automaticallyAfterDays !== undefined) {
117+
rotationRules = {
118+
automaticallyAfterDays,
119+
};
120+
}
121+
108122
new CfnRotationSchedule(this, 'Resource', {
109123
secretId: props.secret.secretArn,
110124
rotationLambdaArn: props.rotationLambda?.functionArn,
111125
hostedRotationLambda: props.hostedRotation?.bind(props.secret, this),
112-
rotationRules: {
113-
automaticallyAfterDays: props.automaticallyAfter && props.automaticallyAfter.toDays() || 30,
114-
},
126+
rotationRules,
115127
});
116128

117129
// Prevent secrets deletions when rotation is in place

Diff for: packages/@aws-cdk/aws-secretsmanager/test/rotation-schedule.test.ts

+40
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as ec2 from '@aws-cdk/aws-ec2';
33
import * as kms from '@aws-cdk/aws-kms';
44
import * as lambda from '@aws-cdk/aws-lambda';
55
import * as cdk from '@aws-cdk/core';
6+
import { Duration } from '@aws-cdk/core';
67
import * as secretsmanager from '../lib';
78

89
let stack: cdk.Stack;
@@ -514,3 +515,42 @@ describe('hosted rotation', () => {
514515
.toThrow(/Cannot use connections for a hosted rotation that is not deployed in a VPC/);
515516
});
516517
});
518+
519+
describe('manual rotations', () => {
520+
test('automaticallyAfter with any duration of zero leaves RotationRules unset', () => {
521+
const checkRotationNotSet = (automaticallyAfter: Duration) => {
522+
// GIVEN
523+
const localStack = new cdk.Stack();
524+
const secret = new secretsmanager.Secret(localStack, 'Secret');
525+
const rotationLambda = new lambda.Function(localStack, 'Lambda', {
526+
runtime: lambda.Runtime.NODEJS_10_X,
527+
code: lambda.Code.fromInline('export.handler = event => event;'),
528+
handler: 'index.handler',
529+
});
530+
531+
// WHEN
532+
new secretsmanager.RotationSchedule(localStack, 'RotationSchedule', {
533+
secret,
534+
rotationLambda,
535+
automaticallyAfter,
536+
});
537+
538+
// THEN
539+
Template.fromStack(localStack).hasResourceProperties('AWS::SecretsManager::RotationSchedule', Match.objectEquals({
540+
SecretId: { Ref: 'SecretA720EF05' },
541+
RotationLambdaARN: {
542+
'Fn::GetAtt': [
543+
'LambdaD247545B',
544+
'Arn',
545+
],
546+
},
547+
}));
548+
};
549+
550+
checkRotationNotSet(Duration.days(0));
551+
checkRotationNotSet(Duration.hours(0));
552+
checkRotationNotSet(Duration.minutes(0));
553+
checkRotationNotSet(Duration.seconds(0));
554+
checkRotationNotSet(Duration.millis(0));
555+
});
556+
});

0 commit comments

Comments
 (0)