Skip to content

Commit

Permalink
feat(HIPAA Security): ElastiCache check (#347)
Browse files Browse the repository at this point in the history
Closes #246

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
dontirun authored Sep 14, 2021
1 parent ce04f57 commit 03e5f82
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 9 deletions.
1 change: 1 addition & 0 deletions RULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ There are currently no warnings for this rule pack.
| [HIPAA.Security-EC2InstancesInVPC](https://docs.aws.amazon.com/config/latest/developerguide/ec2-instances-in-vpc.html) | The EC2 instance is not within a VPC. | Deploy Amazon Elastic Compute Cloud (Amazon EC2) instances within an Amazon Virtual Private Cloud (Amazon VPC) to enable secure communication between an instance and other services within the amazon VPC, without requiring an internet gateway, NAT device, or VPN connection. All traffic remains securely within the AWS Cloud. Because of their logical isolation, domains that reside within anAmazon VPC have an extra layer of security when compared to domains that use public endpoints. Assign Amazon EC2 instances to an Amazon VPC to properly manage access. | 164.308(a)(3)(i), 164.308(a)(4)(ii)(A), 164.308(a)(4)(ii)(C), 164.312(a)(1), 164.312(e)(1) |
| [HIPAA.Security-ECSTaskDefinitionUserForHostMode](https://docs.aws.amazon.com/config/latest/developerguide/ecs-task-definition-user-for-host-mode-check.html) | The ECS task definition is configured for host networking and has at least one container with definitions with 'privileged' set to false or empty or 'user' set to root or empty. | If a task definition has elevated privileges it is because you have specifically opted-in to those configurations. This rule checks for unexpected privilege escalation when a task definition has host networking enabled but the customer has not opted-in to elevated privileges. | 164.308(a)(3)(i), 164.308(a)(3)(ii)(A), 164.308(a)(4)(ii)(A), 164.308(a)(4)(ii)(C), 164.312(a)(1) |
| [HIPAA.Security-EFSEncrypted](https://docs.aws.amazon.com/config/latest/developerguide/efs-encrypted-check.html) | The EFS does not have encryption at rest enabled. | Because sensitive data can exist and to help protect data at rest, ensure encryption is enabled for your Amazon Elastic File System (EFS). | 164.312(a)(2)(iv), 164.312(e)(2)(ii) |
| [HIPAA.Security-ElastiCacheRedisClusterAutomaticBackup](https://docs.aws.amazon.com/config/latest/developerguide/elasticache-redis-cluster-automatic-backup-check.html) | The ElastiCache Redis cluster does not retain automatic backups for at least 15 days. | Automatic backups can help guard against data loss. If a failure occurs, you can create a new cluster, which restores your data from the most recent backup. | 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.308(a)(7)(ii)(B) |

### Excluded Rules

Expand Down
32 changes: 25 additions & 7 deletions src/HIPAA-Security/hipaa-security.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
} from './rules/ec2';
import { hipaaSecurityECSTaskDefinitionUserForHostMode } from './rules/ecs';
import { hipaaSecurityEFSEncrypted } from './rules/efs';
import { hipaaSecurityElastiCacheRedisClusterAutomaticBackup } from './rules/elasticache';

/**
* Check for HIPAA Security compliance.
Expand All @@ -58,7 +59,7 @@ export class HIPAASecurityChecks extends NagPack {
this.checkEC2(node, ignores);
this.checkECS(node, ignores);
this.checkEFS(node, ignores);
// this.checkElastiCache(node, ignores);
this.checkElastiCache(node, ignores);
// this.checkElasticBeanstalk(node, ignores);
// this.checkElasticsearch(node, ignores);
// this.checkELB(node, ignores);
Expand Down Expand Up @@ -445,12 +446,29 @@ export class HIPAASecurityChecks extends NagPack {
}
}

// /**
// * Check ElastiCache Resources
// * @param node the IConstruct to evaluate
// * @param ignores list of ignores for the resource
// */
// private checkElastiCache(node: CfnResource, ignores: any): void {}
/**
* Check ElastiCache Resources
* @param node the IConstruct to evaluate
* @param ignores list of ignores for the resource
*/
private checkElastiCache(node: CfnResource, ignores: any) {
if (
!this.ignoreRule(
ignores,
'HIPAA.Security-ElasticacheRedisClusterAutomaticBackup'
) &&
!hipaaSecurityElastiCacheRedisClusterAutomaticBackup(node)
) {
const ruleId = 'HIPAA.Security-ElasticacheRedisClusterAutomaticBackup';
const info =
'The ElastiCache Redis cluster does not retain automatic backups for at least 15 days - (Control IDs: 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.308(a)(7)(ii)(B)).';
const explanation =
'Automatic backups can help guard against data loss. If a failure occurs, you can create a new cluster, which restores your data from the most recent backup.';
Annotations.of(node).addError(
this.createMessage(ruleId, info, explanation)
);
}
}

// /**
// * Check Elastic Beanstalk Resources
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
import { CfnCacheCluster, CfnReplicationGroup } from '@aws-cdk/aws-elasticache';
import { CfnResource } from '@aws-cdk/core';

/**
* ElastiCache Redis clusters retain automatic backups for at least 15 days - (Control IDs: 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.308(a)(7)(ii)(B))
* @param node the CfnResource to check
*/
export default function (node: CfnResource): boolean {
if (node instanceof CfnCacheCluster) {
const engine = node.engine.toLowerCase();
const retention = node.snapshotRetentionLimit;
if (engine == 'redis' && (retention == undefined || retention < 15)) {
return false;
}
} else if (node instanceof CfnReplicationGroup) {
const retention = node.snapshotRetentionLimit;
if (retention == undefined || retention < 15) {
return false;
}
}
return true;
}
1 change: 1 addition & 0 deletions src/HIPAA-Security/rules/elasticache/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
export { default as hipaaSecurityElastiCacheRedisClusterAutomaticBackup } from './hipaaSecurityElastiCacheRedisClusterAutomaticBackup';
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { CfnCacheCluster, CfnReplicationGroup } from '@aws-cdk/aws-elasticache';
import { CfnResource } from '@aws-cdk/core';

/**
* ElastiCache Redis clusters retain automatic backups for at least 15 days (Control IDs: CP-9(b), CP-10, SI-12)
* ElastiCache Redis clusters retain automatic backups for at least 15 days - (Control IDs: CP-9(b), CP-10, SI-12)
* @param node the CfnResource to check
*/
export default function (node: CfnResource): boolean {
Expand Down
76 changes: 76 additions & 0 deletions test/HIPAA-Security/HIPAA-Security-Elasticache.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
import { SynthUtils } from '@aws-cdk/assert';
import { CfnCacheCluster, CfnReplicationGroup } from '@aws-cdk/aws-elasticache';
import { Aspects, Stack } from '@aws-cdk/core';
import { HIPAASecurityChecks } from '../../src';

describe('Amazon ElastiCache', () => {
test('HIPAA.Security-ElasticacheRedisClusterAutomaticBackup: ElastiCache Redis clusters retain automatic backups for at least 15 days', () => {
const nonCompliant = new Stack();
Aspects.of(nonCompliant).add(new HIPAASecurityChecks());
new CfnCacheCluster(nonCompliant, 'rAec', {
cacheNodeType: 'cache.t3.micro',
engine: 'redis',
numCacheNodes: 42,
snapshotRetentionLimit: 14,
port: 11211,
});
const messages = SynthUtils.synthesize(nonCompliant).messages;
expect(messages).toContainEqual(
expect.objectContaining({
entry: expect.objectContaining({
data: expect.stringContaining(
'HIPAA.Security-ElasticacheRedisClusterAutomaticBackup:'
),
}),
})
);

const nonCompliant2 = new Stack();
Aspects.of(nonCompliant2).add(new HIPAASecurityChecks());
new CfnReplicationGroup(nonCompliant2, 'rAecGroup', {
replicationGroupDescription: 'lorem ipsum dolor sit amet',
cacheNodeType: 'cache.t3.micro',
engine: 'redis',
});
const messages2 = SynthUtils.synthesize(nonCompliant2).messages;
expect(messages2).toContainEqual(
expect.objectContaining({
entry: expect.objectContaining({
data: expect.stringContaining(
'HIPAA.Security-ElasticacheRedisClusterAutomaticBackup:'
),
}),
})
);

const compliant = new Stack();
Aspects.of(compliant).add(new HIPAASecurityChecks());
new CfnCacheCluster(compliant, 'rAec', {
cacheNodeType: 'cache.t3.micro',
engine: 'redis',
numCacheNodes: 42,
snapshotRetentionLimit: 16,
port: 42,
});
new CfnReplicationGroup(compliant, 'rAecGroup', {
replicationGroupDescription: 'lorem ipsum dolor sit amet',
cacheNodeType: 'cache.t3.micro',
engine: 'redis',
snapshotRetentionLimit: 16,
});
const messages3 = SynthUtils.synthesize(compliant).messages;
expect(messages3).not.toContainEqual(
expect.objectContaining({
entry: expect.objectContaining({
data: expect.stringContaining(
'HIPAA.Security-ElasticacheRedisClusterAutomaticBackup:'
),
}),
})
);
});
});
2 changes: 1 addition & 1 deletion test/NIST-800-53/NIST-800-53-Elasticache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0
import { SynthUtils } from '@aws-cdk/assert';
import { CfnCacheCluster, CfnReplicationGroup } from '@aws-cdk/aws-elasticache';
import { Aspects, Stack } from '@aws-cdk/core';
import { NIST80053Checks } from '../../src/NIST-800-53/nist-800-53';
import { NIST80053Checks } from '../../src';

describe('Amazon ElastiCache', () => {
test('NIST.800.53-ElastiCacheRedisClusterAutomaticBackup: ElastiCache Redis clusters retain automatic backups for at least 15 days', () => {
Expand Down

0 comments on commit 03e5f82

Please sign in to comment.