Skip to content

Commit

Permalink
feat(sqs): add enforceSSL property to enforce encryption of data in t…
Browse files Browse the repository at this point in the history
…ransit (#22363)

Enforcing encryption in transit is an [SQS best practice](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-security-best-practices.html#enforce-encryption-data-in-transit). It also appears in [cdk-nag](https://github.com/cdklabs/cdk-nag/blob/main/RULES.md) rule as [AwsSolutions-SQS4](https://github.com/cdklabs/cdk-nag/blob/main/RULES.md#errors).

`enforceSSL` property helps developers implement it easily.

----

### All Submissions:

* [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md)

### Adding new Unconventional Dependencies:

* [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies)

### New Features

* [x] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)?
	* [x] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)?

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
clueleaf authored Oct 7, 2022
1 parent 614ba92 commit f1886cf
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 5 deletions.
12 changes: 12 additions & 0 deletions packages/@aws-cdk/aws-sqs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@ new sqs.Queue(this, 'Queue', {
});
```

## Encryption in transit

If you want to enforce encryption of data in transit, set the `enforceSSL` property to `true`.
A resource policy statement that allows only encrypted connections over HTTPS (TLS)
will be added to the queue.

```ts
new sqs.Queue(this, 'Queue', {
enforceSSL: true,
});
```

## First-In-First-Out (FIFO) queues

FIFO queues give guarantees on the order in which messages are dequeued, and have additional
Expand Down
30 changes: 30 additions & 0 deletions packages/@aws-cdk/aws-sqs/lib/queue.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as iam from '@aws-cdk/aws-iam';
import * as kms from '@aws-cdk/aws-kms';
import { Duration, RemovalPolicy, Stack, Token, ArnFormat } from '@aws-cdk/core';
import { Construct } from 'constructs';
Expand Down Expand Up @@ -169,6 +170,14 @@ export interface QueueProps {
* @default RemovalPolicy.DESTROY
*/
readonly removalPolicy?: RemovalPolicy;

/**
* Enforce encryption of data in transit.
* @see https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-security-best-practices.html#enforce-encryption-data-in-transit
*
* @default false
*/
readonly enforceSSL?: boolean;
}

/**
Expand Down Expand Up @@ -432,6 +441,11 @@ export class Queue extends QueueBase {

throw new Error(`Unexpected 'encryptionType': ${encryption}`);
}

// Enforce encryption of data in transit
if (props.enforceSSL) {
this.enforceSSLStatement();
}
}

/**
Expand Down Expand Up @@ -475,6 +489,22 @@ export class Queue extends QueueBase {
fifoQueue,
};
}

/**
* Adds an iam statement to enforce encryption of data in transit.
*/
private enforceSSLStatement() {
const statement = new iam.PolicyStatement({
actions: ['sqs:*'],
conditions: {
Bool: { 'aws:SecureTransport': 'false' },
},
effect: iam.Effect.DENY,
resources: [this.queueArn],
principals: [new iam.AnyPrincipal()],
});
this.addToResourcePolicy(statement);
}
}

interface FifoProps {
Expand Down
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-sqs/test/integ.sqs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const sqsManagedEncryptedQueue = new Queue(stack, 'SqsManagedEncryptedQueue', {
const unencryptedQueue = new Queue(stack, 'UnencryptedQueue', {
encryption: QueueEncryption.UNENCRYPTED,
});
const ssl = new Queue(stack, 'SSLQueue', { enforceSSL: true });

const role = new Role(stack, 'Role', {
assumedBy: new AccountRootPrincipal(),
Expand All @@ -39,6 +40,7 @@ fifo.grantConsumeMessages(role);
highThroughputFifo.grantConsumeMessages(role);
sqsManagedEncryptedQueue.grantConsumeMessages(role);
unencryptedQueue.grantConsumeMessages(role);
ssl.grantConsumeMessages(role);

new CfnOutput(stack, 'QueueUrl', { value: queue.queueUrl });

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"version": "21.0.0",
"files": {
"a660932c356f8eec80b4314b041c64311fd29803603b65a95351137afa8eba04": {
"7fd5f7d37f2f344aa43e18636af702436c91c871b1380d772857c431c603bb27": {
"source": {
"path": "aws-cdk-sqs.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "a660932c356f8eec80b4314b041c64311fd29803603b65a95351137afa8eba04.json",
"objectKey": "7fd5f7d37f2f344aa43e18636af702436c91c871b1380d772857c431c603bb27.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,44 @@
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete"
},
"SSLQueue4E9BF022": {
"Type": "AWS::SQS::Queue",
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete"
},
"SSLQueuePolicy5ABFDF4F": {
"Type": "AWS::SQS::QueuePolicy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": "sqs:*",
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
},
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Resource": {
"Fn::GetAtt": [
"SSLQueue4E9BF022",
"Arn"
]
}
}
],
"Version": "2012-10-17"
},
"Queues": [
{
"Ref": "SSLQueue4E9BF022"
}
]
}
},
"Role1ABCC5F0": {
"Type": "AWS::IAM::Role",
"Properties": {
Expand Down Expand Up @@ -168,6 +206,12 @@
"Arn"
]
},
{
"Fn::GetAtt": [
"SSLQueue4E9BF022",
"Arn"
]
},
{
"Fn::GetAtt": [
"SqsManagedEncryptedQueue587679B3",
Expand Down
14 changes: 13 additions & 1 deletion packages/@aws-cdk/aws-sqs/test/sqs.integ.snapshot/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"validateOnSynth": false,
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/a660932c356f8eec80b4314b041c64311fd29803603b65a95351137afa8eba04.json",
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/7fd5f7d37f2f344aa43e18636af702436c91c871b1380d772857c431c603bb27.json",
"requiresBootstrapStackVersion": 6,
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
"additionalDependencies": [
Expand Down Expand Up @@ -81,6 +81,18 @@
"data": "UnencryptedQueue57F92F9C"
}
],
"/aws-cdk-sqs/SSLQueue/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "SSLQueue4E9BF022"
}
],
"/aws-cdk-sqs/SSLQueue/Policy/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "SSLQueuePolicy5ABFDF4F"
}
],
"/aws-cdk-sqs/Role/Resource": [
{
"type": "aws:cdk:logicalId",
Expand Down
83 changes: 81 additions & 2 deletions packages/@aws-cdk/aws-sqs/test/sqs.integ.snapshot/tree.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"path": "Tree",
"constructInfo": {
"fqn": "constructs.Construct",
"version": "10.1.108"
"version": "10.1.102"
}
},
"aws-cdk-sqs": {
Expand Down Expand Up @@ -226,6 +226,79 @@
"version": "0.0.0"
}
},
"SSLQueue": {
"id": "SSLQueue",
"path": "aws-cdk-sqs/SSLQueue",
"children": {
"Resource": {
"id": "Resource",
"path": "aws-cdk-sqs/SSLQueue/Resource",
"attributes": {
"aws:cdk:cloudformation:type": "AWS::SQS::Queue",
"aws:cdk:cloudformation:props": {}
},
"constructInfo": {
"fqn": "@aws-cdk/aws-sqs.CfnQueue",
"version": "0.0.0"
}
},
"Policy": {
"id": "Policy",
"path": "aws-cdk-sqs/SSLQueue/Policy",
"children": {
"Resource": {
"id": "Resource",
"path": "aws-cdk-sqs/SSLQueue/Policy/Resource",
"attributes": {
"aws:cdk:cloudformation:type": "AWS::SQS::QueuePolicy",
"aws:cdk:cloudformation:props": {
"policyDocument": {
"Statement": [
{
"Action": "sqs:*",
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
},
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Resource": {
"Fn::GetAtt": [
"SSLQueue4E9BF022",
"Arn"
]
}
}
],
"Version": "2012-10-17"
},
"queues": [
{
"Ref": "SSLQueue4E9BF022"
}
]
}
},
"constructInfo": {
"fqn": "@aws-cdk/aws-sqs.CfnQueuePolicy",
"version": "0.0.0"
}
}
},
"constructInfo": {
"fqn": "@aws-cdk/aws-sqs.QueuePolicy",
"version": "0.0.0"
}
}
},
"constructInfo": {
"fqn": "@aws-cdk/aws-sqs.Queue",
"version": "0.0.0"
}
},
"Role": {
"id": "Role",
"path": "aws-cdk-sqs/Role",
Expand Down Expand Up @@ -316,6 +389,12 @@
"Arn"
]
},
{
"Fn::GetAtt": [
"SSLQueue4E9BF022",
"Arn"
]
},
{
"Fn::GetAtt": [
"SqsManagedEncryptedQueue587679B3",
Expand Down Expand Up @@ -395,7 +474,7 @@
"path": "SqsTest/DefaultTest/Default",
"constructInfo": {
"fqn": "constructs.Construct",
"version": "10.1.108"
"version": "10.1.102"
}
},
"DeployAssert": {
Expand Down
45 changes: 45 additions & 0 deletions packages/@aws-cdk/aws-sqs/test/sqs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,51 @@ describe('queue encryption', () => {
});
});

describe('encryption in transit', () => {
test('enforceSSL can be enabled', () => {
const stack = new Stack();
new sqs.Queue(stack, 'Queue', { enforceSSL: true });

Template.fromStack(stack).templateMatches({
'Resources': {
'Queue4A7E3555': {
'Type': 'AWS::SQS::Queue',
'UpdateReplacePolicy': 'Delete',
'DeletionPolicy': 'Delete',
},
'QueuePolicy25439813': {
'Type': 'AWS::SQS::QueuePolicy',
'Properties': {
'PolicyDocument': {
'Statement': [
{
'Action': 'sqs:*',
'Condition': {
'Bool': {
'aws:SecureTransport': 'false',
},
},
'Effect': 'Deny',
'Principal': {
'AWS': '*',
},
'Resource': {
'Fn::GetAtt': [
'Queue4A7E3555',
'Arn',
],
},
},
],
'Version': '2012-10-17',
},
},
},
},
});
});
});

test('test ".fifo" suffixed queues register as fifo', () => {
const stack = new Stack();
const queue = new sqs.Queue(stack, 'Queue', {
Expand Down

0 comments on commit f1886cf

Please sign in to comment.