Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@ class SecretsManagerStack extends cdk.Stack {

/// !show
// Default secret
const secret = new secretsmanager.Secret(this, 'Secret');
const secret = new secretsmanager.Secret(this, 'Secret', {
blockPublicPolicy: true,
});
secret.addToResourcePolicy(new iam.PolicyStatement({
actions: ['secretsmanager:GetSecretValue'],
principals: [new iam.AnyPrincipal()],
resources: ['*'],
}));
secret.grantRead(role);

const user = new iam.User(this, 'User', {
Expand Down
14 changes: 14 additions & 0 deletions packages/aws-cdk-lib/aws-secretsmanager/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,20 @@ secret.grantRead(role);
secret.grantWrite(role);
```

## Block public resource policies

To ask Secrets Manager to reject resource policies that grant public access,
set `blockPublicPolicy` when creating a secret or a standalone resource policy:

```ts
const secret = new secretsmanager.Secret(this, 'Secret', {
blockPublicPolicy: true,
});
```

When the secret creates its resource policy lazily, the setting is forwarded to
`AWS::SecretsManager::ResourcePolicy`.

If, as in the following example, your secret was created with a KMS key:

```ts
Expand Down
8 changes: 8 additions & 0 deletions packages/aws-cdk-lib/aws-secretsmanager/lib/policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ export interface ResourcePolicyProps {
* The secret to attach a resource-based permissions policy
*/
readonly secret: ISecret;

/**
* Specifies whether to block resource-based policies that allow broad access to the secret.
*
* @default - AWS Secrets Manager default
*/
readonly blockPublicPolicy?: boolean;
}

/**
Expand Down Expand Up @@ -47,6 +54,7 @@ export class ResourcePolicy extends Resource {
new CfnResourcePolicy(this, 'Resource', {
resourcePolicy: this.document,
secretId: props.secret.secretArn,
blockPublicPolicy: props.blockPublicPolicy,
});
}
}
18 changes: 15 additions & 3 deletions packages/aws-cdk-lib/aws-secretsmanager/lib/secret.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,13 @@ export interface SecretProps {
*/
readonly description?: string;

/**
* Specifies whether to block resource-based policies that allow broad access to the secret.
*
* @default - AWS Secrets Manager default
*/
readonly blockPublicPolicy?: boolean;

/**
* The customer-managed encryption key to use for encrypting the secret value.
*
Expand Down Expand Up @@ -359,9 +366,11 @@ abstract class SecretBase extends Resource implements ISecret {

private policy?: ResourcePolicy;
private _arnForPolicies: string;
private readonly blockPublicPolicy?: boolean;

constructor(scope: Construct, id: string, props: ResourceProps = {}) {
constructor(scope: Construct, id: string, props: ResourceProps = {}, blockPublicPolicy?: boolean) {
super(scope, id, props);
this.blockPublicPolicy = blockPublicPolicy;
// eslint-disable-next-line no-restricted-syntax
this._arnForPolicies = Lazy.uncachedString({
produce: (context: IResolveContext) => {
Expand Down Expand Up @@ -484,7 +493,10 @@ abstract class SecretBase extends Resource implements ISecret {

public addToResourcePolicy(statement: iam.PolicyStatement): iam.AddToResourcePolicyResult {
if (!this.policy && this.autoCreatePolicy) {
this.policy = new ResourcePolicy(this, 'Policy', { secret: this });
this.policy = new ResourcePolicy(this, 'Policy', {
secret: this,
blockPublicPolicy: this.blockPublicPolicy,
});
}

if (this.policy) {
Expand Down Expand Up @@ -676,7 +688,7 @@ export class Secret extends SecretBase {
constructor(scope: Construct, id: string, props: SecretProps = {}) {
super(scope, id, {
physicalName: props.secretName,
});
}, props.blockPublicPolicy);
// Enhanced CDK Analytics Telemetry
addConstructMetadata(this, props);

Expand Down
15 changes: 15 additions & 0 deletions packages/aws-cdk-lib/aws-secretsmanager/test/policy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,18 @@ describe.each([
Template.fromStack(stack).resourceCountIs('AWS::SecretsManager::ResourcePolicy', expectedResourcePolicyCount);
});
});

test('passes blockPublicPolicy to the L1 resource policy', () => {
const app = new cdk.App();
const stack = new cdk.Stack(app);
const secret = new secretsmanager.Secret(stack, 'Secret');

new secretsmanager.ResourcePolicy(stack, 'Policy', {
secret,
blockPublicPolicy: true,
});

Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::ResourcePolicy', {
BlockPublicPolicy: true,
});
});
16 changes: 16 additions & 0 deletions packages/aws-cdk-lib/aws-secretsmanager/test/secret.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ test('default secret', () => {
});
});

test('secret with blockPublicPolicy passes it to the resource policy', () => {
const secret = new secretsmanager.Secret(stack, 'Secret', {
blockPublicPolicy: true,
});

secret.addToResourcePolicy(new iam.PolicyStatement({
actions: ['secretsmanager:GetSecretValue'],
principals: [new iam.AccountRootPrincipal()],
resources: ['*'],
}));

Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::ResourcePolicy', {
BlockPublicPolicy: true,
});
});

test('secret without replica regions omits ReplicaRegions', () => {
// WHEN
new secretsmanager.Secret(stack, 'Secret');
Expand Down
Loading