Skip to content

Commit

Permalink
feat(HIPAA Security): ELB checks (#349)
Browse files Browse the repository at this point in the history
Closes #158
Closes #159
Closes #253
Closes #254
Closes #255
Closes #256
Closes #257
Closes #258

----

*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 03e5f82 commit 493a269
Show file tree
Hide file tree
Showing 19 changed files with 974 additions and 17 deletions.
10 changes: 10 additions & 0 deletions .projen/deps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .projenrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const project = new AwsCdkConstructLibrary({
'@aws-cdk/aws-apigatewayv2-integrations',
'@aws-cdk/aws-athena',
'@aws-cdk/aws-autoscaling',
'@aws-cdk/aws-certificatemanager',
'@aws-cdk/aws-codebuild',
'@aws-cdk/aws-cloud9',
'@aws-cdk/aws-cloudfront',
Expand Down
12 changes: 10 additions & 2 deletions RULES.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

138 changes: 131 additions & 7 deletions src/HIPAA-Security/hipaa-security.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ import {
import { hipaaSecurityECSTaskDefinitionUserForHostMode } from './rules/ecs';
import { hipaaSecurityEFSEncrypted } from './rules/efs';
import { hipaaSecurityElastiCacheRedisClusterAutomaticBackup } from './rules/elasticache';
import {
hipaaSecurityALBHttpDropInvalidHeaderEnabled,
hipaaSecurityALBHttpToHttpsRedirection,
hipaaSecurityELBACMCertificateRequired,
hipaaSecurityELBCrossZoneBalancingEnabled,
hipaaSecurityELBDeletionProtectionEnabled,
hipaaSecurityELBLoggingEnabled,
hipaaSecurityELBTlsHttpsListenersOnly,
hipaaSecurityELBv2ACMCertificateRequired,
} from './rules/elb';

/**
* Check for HIPAA Security compliance.
Expand All @@ -62,7 +72,7 @@ export class HIPAASecurityChecks extends NagPack {
this.checkElastiCache(node, ignores);
// this.checkElasticBeanstalk(node, ignores);
// this.checkElasticsearch(node, ignores);
// this.checkELB(node, ignores);
this.checkELB(node, ignores);
// this.checkEMR(node, ignores);
// this.checkIAM(node, ignores);
// this.checkLambda(node, ignores);
Expand Down Expand Up @@ -484,12 +494,126 @@ export class HIPAASecurityChecks extends NagPack {
// */
// private checkElasticsearch(node: CfnResource, ignores: any): void {}

// /**
// * Check ELB Resources
// * @param node the IConstruct to evaluate
// * @param ignores list of ignores for the resource
// */
// private checkELB(node: CfnResource, ignores: any): void {}
/**
* Check Elastic Load Balancer Resources
* @param node the IConstruct to evaluate
* @param ignores list of ignores for the resource
*/
private checkELB(node: CfnResource, ignores: any): void {
if (
!this.ignoreRule(
ignores,
'HIPAA.Security-ALBHttpDropInvalidHeaderEnabled'
) &&
!hipaaSecurityALBHttpDropInvalidHeaderEnabled(node)
) {
const ruleId = 'HIPAA.Security-ALBHttpDropInvalidHeaderEnabled';
const info =
'The ALB does not have invalid HTTP header dropping enabled - (Control IDs: 164.312(a)(2)(iv), 164.312(e)(1), 164.312(e)(2)(i), 164.312(e)(2)(ii)).';
const explanation =
'Ensure that your Application Load Balancers (ALB) are configured to drop http headers. Because sensitive data can exist, enable encryption in transit to help protect that data.';
Annotations.of(node).addError(
this.createMessage(ruleId, info, explanation)
);
}
if (
!this.ignoreRule(ignores, 'HIPAA.Security-ALBHttpToHttpsRedirection') &&
!hipaaSecurityALBHttpToHttpsRedirection(node)
) {
const ruleId = 'HIPAA.Security-ALBHttpToHttpsRedirection';
const info =
"The ALB's HTTP listeners are not configured to redirect to HTTPS - (Control IDs: 164.312(a)(2)(iv), 164.312(e)(1), 164.312(e)(2)(i), 164.312(e)(2)(ii)).";
const explanation =
'To help protect data in transit, ensure that your Application Load Balancer automatically redirects unencrypted HTTP requests to HTTPS. Because sensitive data can exist, enable encryption in transit to help protect that data.';
Annotations.of(node).addError(
this.createMessage(ruleId, info, explanation)
);
}
if (
!this.ignoreRule(ignores, 'HIPAA.Security-ELBACMCertificateRequired') &&
!hipaaSecurityELBACMCertificateRequired(node)
) {
const ruleId = 'HIPAA.Security-ELBACMCertificateRequired';
const info =
'The CLB does not utilize an SSL certificate provided by ACM (Amazon Certificate Manager) - (Control IDs: 164.312(a)(2)(iv), 164.312(e)(1), 164.312(e)(2)(i), 164.312(e)(2)(ii)).';
const explanation =
'Because sensitive data can exist and to help protect data at transit, ensure encryption is enabled for your Elastic Load Balancing. Use AWS Certificate Manager to manage, provision and deploy public and private SSL/TLS certificates with AWS services and internal resources.';
Annotations.of(node).addError(
this.createMessage(ruleId, info, explanation)
);
}
if (
!this.ignoreRule(
ignores,
'HIPAA.Security-ELBCrossZoneBalancingEnabled'
) &&
!hipaaSecurityELBCrossZoneBalancingEnabled(node)
) {
const ruleId = 'HIPAA.Security-ELBCrossZoneBalancingEnabled';
const info =
'The CLB does not balance traffic between at least 2 Availability Zones - (Control IDs: 164.308(a)(7)(i), 164.308(a)(7)(ii)(C)).';
const explanation =
'The cross-zone load balancing reduces the need to maintain equivalent numbers of instances in each enabled availability zone.';
Annotations.of(node).addError(
this.createMessage(ruleId, info, explanation)
);
}
if (
!this.ignoreRule(
ignores,
'HIPAA.Security-ELBDeletionProtectionEnabled'
) &&
!hipaaSecurityELBDeletionProtectionEnabled(node)
) {
const ruleId = 'HIPAA.Security-ELBDeletionProtectionEnabled';
const info =
'The ALB, NLB, or GLB does not have deletion protection enabled - (Control IDs: 164.308(a)(7)(i), 164.308(a)(7)(ii)(C)).';
const explanation =
'Use this feature to prevent your load balancer from being accidentally or maliciously deleted, which can lead to loss of availability for your applications.';
Annotations.of(node).addError(
this.createMessage(ruleId, info, explanation)
);
}
if (
!this.ignoreRule(ignores, 'HIPAA.Security-ELBLoggingEnabled') &&
!hipaaSecurityELBLoggingEnabled(node)
) {
const ruleId = 'HIPAA.Security-ELBLoggingEnabled';
const info =
'The ELB does not have logging enabled - (Control ID: 164.312(b)).';
const explanation =
"Elastic Load Balancing activity is a central point of communication within an environment. Ensure ELB logging is enabled. The collected data provides detailed information about requests sent to The ELB. Each log contains information such as the time the request was received, the client's IP address, latencies, request paths, and server responses.";
Annotations.of(node).addError(
this.createMessage(ruleId, info, explanation)
);
}
if (
!this.ignoreRule(ignores, 'HIPAA.Security-ELBTlsHttpsListenersOnly') &&
!hipaaSecurityELBTlsHttpsListenersOnly(node)
) {
const ruleId = 'HIPAA.Security-ELBTlsHttpsListenersOnly';
const info =
'The CLB does not restrict its listeners to only the SSL and HTTPS protocols - (Control IDs: 164.312(a)(2)(iv), 164.312(e)(1), 164.312(e)(2)(i), 164.312(e)(2)(ii)).';
const explanation =
'Because sensitive data can exist, enable encryption in transit to help protect that data.';
Annotations.of(node).addError(
this.createMessage(ruleId, info, explanation)
);
}
if (
!this.ignoreRule(ignores, 'HIPAA.Security-ELBv2ACMCertificateRequired') &&
!hipaaSecurityELBv2ACMCertificateRequired(node)
) {
const ruleId = 'HIPAA.Security-ELBv2ACMCertificateRequired';
const info =
'The ALB, NLB, or GLB listener does not utilize an SSL certificate provided by ACM (Amazon Certificate Manager) - (Control IDs: 164.312(a)(2)(iv), 164.312(e)(2)(ii)).';
const explanation =
'Because sensitive data can exist and to help protect data at transit, ensure encryption is enabled for your Elastic Load Balancing. Use AWS Certificate Manager to manage, provision and deploy public and private SSL/TLS certificates with AWS services and internal resources.';
Annotations.of(node).addError(
this.createMessage(ruleId, info, explanation)
);
}
}

// /**
// * Check EMR Resources
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

import { CfnLoadBalancer } from '@aws-cdk/aws-elasticloadbalancingv2';
import { IConstruct, Stack } from '@aws-cdk/core';

/**
* Application Load Balancers are enabled to drop invalid headers - (Control IDs: 164.312(a)(2)(iv), 164.312(e)(1), 164.312(e)(2)(i), 164.312(e)(2)(ii))
* @param node the CfnResource to check
*/
export default function (node: IConstruct): boolean {
if (node instanceof CfnLoadBalancer) {
const type = Stack.of(node).resolve(node.type);
if (type == undefined || type == 'application') {
const attributes = Stack.of(node).resolve(node.loadBalancerAttributes);
if (attributes != undefined) {
const reg =
/"routing\.http\.drop_invalid_header_fields\.enabled","value":"true"/gm;
if (JSON.stringify(attributes).search(reg) == -1) {
return false;
}
} else {
return false;
}
}
}
return true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

import { CfnListener } from '@aws-cdk/aws-elasticloadbalancingv2';
import { IConstruct, Stack } from '@aws-cdk/core';

/**
* ALB HTTP listeners are configured to redirect to HTTPS - (Control IDs: 164.312(a)(2)(iv), 164.312(e)(1), 164.312(e)(2)(i), 164.312(e)(2)(ii))
* @param node the CfnResource to check
*/
export default function (node: IConstruct): boolean {
if (node instanceof CfnListener) {
let found = false;
const protocol = Stack.of(node).resolve(node.protocol);
const actions = Stack.of(node).resolve(node.defaultActions);

if (protocol == 'HTTP') {
for (const action of actions) {
if (
action.type == 'redirect' &&
action.redirectConfig.protocol == 'HTTPS'
) {
found = true;
}
}
if (!found) return false;
}
}

return true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

import { CfnLoadBalancer } from '@aws-cdk/aws-elasticloadbalancing';
import { IConstruct, Stack } from '@aws-cdk/core';

/**
* CLBs use ACM-managed certificates - (Control IDs: 164.312(a)(2)(iv), 164.312(e)(1), 164.312(e)(2)(i), 164.312(e)(2)(ii))
* @param node the CfnResource to check
*/
export default function (node: IConstruct): boolean {
if (node instanceof CfnLoadBalancer) {
//For each listener, ensure that it's utilizing an ACM SSL/HTTPS cert
const listeners = Stack.of(node).resolve(node.listeners);
if (listeners != undefined) {
//Iterate through listeners, checking if secured ACM certs are used
for (const listener of listeners) {
const resolvedListener = Stack.of(node).resolve(listener);
const listenerARN = resolvedListener.sslCertificateId;
//Use the ARN to check if this is an ACM managed cert
if (listenerARN == undefined) {
return false;
} else {
const acmRegex = /^arn:[^:]+:acm:.+$/;
if (!acmRegex.test(listenerARN)) {
return false;
}
}
}
}
}
return true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

import { CfnLoadBalancer } from '@aws-cdk/aws-elasticloadbalancing';
import { IConstruct, Stack } from '@aws-cdk/core';

/**
* CLBs use at least two AZs with the Cross-Zone Load Balancing feature enabled - (Control IDs: 164.308(a)(7)(i), 164.308(a)(7)(ii)(C))
* @param node the CfnResource to check
*/
export default function (node: IConstruct): boolean {
if (node instanceof CfnLoadBalancer) {
if (node.crossZone == undefined) {
return false;
}
if (node.subnets == undefined) {
if (
node.availabilityZones == undefined ||
node.availabilityZones.length < 2
) {
return false;
}
} else if (node.subnets.length < 2) {
return false;
}
const crossZone = Stack.of(node).resolve(node.crossZone);
if (crossZone != true) {
return false;
}
}
return true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

import { CfnLoadBalancer } from '@aws-cdk/aws-elasticloadbalancingv2';
import { IConstruct, Stack } from '@aws-cdk/core';

/**
* ALBs, NLBs, and GLBs have deletion protection enabled - (Control IDs: 164.308(a)(7)(i), 164.308(a)(7)(ii)(C))
* @param node the CfnResource to check
*/
export default function (node: IConstruct): boolean {
if (node instanceof CfnLoadBalancer) {
const attributes = Stack.of(node).resolve(node.loadBalancerAttributes);
if (attributes != undefined) {
var deletionProtectionEnabled = false;
for (const attr of attributes) {
const resolvedAttr = Stack.of(node).resolve(attr);
if (
resolvedAttr.key != undefined &&
resolvedAttr.key == 'deletion_protection.enabled'
) {
if (resolvedAttr.value == 'true') {
deletionProtectionEnabled = true;
}
}
}
if (!deletionProtectionEnabled) {
return false;
}
} else {
return false;
}
}
return true;
}
Loading

0 comments on commit 493a269

Please sign in to comment.