Skip to content

Commit

Permalink
feat: Granular findings for log export based rules (#679) (#684)
Browse files Browse the repository at this point in the history
* feat: granular findings for DocumentDBClusterLogExports

* feat: granular findings for EKSClusterControlPlaneLogs

* tests: update DocumentDB and EKS tests

* feat: granular findings for OpenSearchSlowLogsToCloudWatch

* feat: granular findings for AuroraMySQLLogging

* feat: granular findings for RDSLoggingEnabled

* test: remove logging statement
  • Loading branch information
dontirun authored Mar 2, 2022
1 parent d189f28 commit d737655
Show file tree
Hide file tree
Showing 16 changed files with 385 additions and 170 deletions.
16 changes: 8 additions & 8 deletions RULES.md

Large diffs are not rendered by default.

14 changes: 9 additions & 5 deletions src/packs/aws-solutions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,8 @@ export class AwsSolutionsChecks extends NagPack {
ruleSuffixOverride: 'EKS2',
info: "The EKS Cluster does not publish 'api', 'audit', 'authenticator, 'controllerManager', and 'scheduler' control plane logs.",
explanation:
'EKS control plane logging provides audit and diagnostic logs directly from the Amazon EKS control plane to CloudWatch Logs in your account. These logs make it easy for you to secure and run your clusters.',
'EKS control plane logging provides audit and diagnostic logs directly from the Amazon EKS control plane to CloudWatch Logs in your account. These logs make it easy for you to secure and run your clusters.' +
"This is a granular rule that returns individual findings that can be suppressed with 'appliesTo'. The findings are in the format 'LogExport::<log>' for exported logs. Example: appliesTo: ['LogExport::api'].",
level: NagMessageLevel.ERROR,
rule: EKSClusterControlPlaneLogs,
node: node,
Expand Down Expand Up @@ -530,7 +531,8 @@ export class AwsSolutionsChecks extends NagPack {
ruleSuffixOverride: 'RDS16',
info: 'The RDS Aurora MySQL serverless cluster does not have audit, error, general, and slowquery Log Exports enabled.',
explanation:
'This allows operators to use CloudWatch to view logs to help diagnose problems in the database.',
'This allows operators to use CloudWatch to view logs to help diagnose problems in the database.' +
"This is a granular rule that returns individual findings that can be suppressed with 'appliesTo'. The findings are in the format 'LogExport::<log>' for exported logs. Example: appliesTo: ['LogExport::audit'].",
level: NagMessageLevel.ERROR,
rule: AuroraMySQLLogging,
node: node,
Expand Down Expand Up @@ -772,7 +774,8 @@ export class AwsSolutionsChecks extends NagPack {
ruleSuffixOverride: 'DOC5',
info: 'The Document DB cluster does not have authenticate, createIndex, and dropCollection Log Exports enabled.',
explanation:
'This allows operators to use CloudWatch to view logs to help diagnose problems in the database. The events recorded by the AWS DocumentDB audit logs include successful and failed authentication attempts, creating indexes or dropping a collection in a database within the DocumentDB cluster.',
'This allows operators to use CloudWatch to view logs to help diagnose problems in the database. The events recorded by the AWS DocumentDB audit logs include successful and failed authentication attempts, creating indexes or dropping a collection in a database within the DocumentDB cluster.' +
"This is a granular rule that returns individual findings that can be suppressed with 'appliesTo'. The findings are in the format 'LogExport::<log>' for exported logs. Example: appliesTo: ['LogExport::authenticate'].",
level: NagMessageLevel.ERROR,
rule: DocumentDBClusterLogExports,
node: node,
Expand Down Expand Up @@ -1173,7 +1176,8 @@ export class AwsSolutionsChecks extends NagPack {
ruleSuffixOverride: 'OS9',
info: 'The OpenSearch Service domain does not minimally publish SEARCH_SLOW_LOGS and INDEX_SLOW_LOGS to CloudWatch Logs.',
explanation:
'These logs enable operators to gain full insight into the performance of these operations.',
'These logs enable operators to gain full insight into the performance of these operations.' +
"This is a granular rule that returns individual findings that can be suppressed with 'appliesTo'. The findings are in the format 'LogExport::<log>' for exported logs. Example: appliesTo: ['LogExport::SEARCH_SLOW_LOGS'].",
level: NagMessageLevel.ERROR,
rule: OpenSearchSlowLogsToCloudWatch,
node: node,
Expand Down Expand Up @@ -1209,7 +1213,7 @@ export class AwsSolutionsChecks extends NagPack {
info: 'The IAM entity contains wildcard permissions and does not have a cdk_nag rule suppression with evidence for those permission.',
explanation:
'Metadata explaining the evidence (e.g. via supporting links) for wildcard permissions allows for transparency to operators. ' +
"This is a granular rule that returns individual findings that can be suppressed with 'appliesTo'. The findings are in the format 'Action::<action>' for policy actions and 'Resource::<resource>' for resources. Example: appliesTo: ['Action::s3:*']",
"This is a granular rule that returns individual findings that can be suppressed with 'appliesTo'. The findings are in the format 'Action::<action>' for policy actions and 'Resource::<resource>' for resources. Example: appliesTo: ['Action::s3:*'].",
level: NagMessageLevel.ERROR,
rule: IAMNoWildcardPermissions,
node: node,
Expand Down
3 changes: 2 additions & 1 deletion src/packs/hipaa-security.ts
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,8 @@ export class HIPAASecurityChecks extends NagPack {
this.applyRule({
info: 'The RDS DB instance does not have all CloudWatch log types exported - (Control IDs: 164.308(a)(3)(ii)(A), 164.308(a)(5)(ii)(C)).',
explanation:
'To help with logging and monitoring within your environment, ensure Amazon Relational Database Service (Amazon RDS) logging is enabled. With Amazon RDS logging, you can capture events such as connections, disconnections, queries, or tables queried.',
'To help with logging and monitoring within your environment, ensure Amazon Relational Database Service (Amazon RDS) logging is enabled. With Amazon RDS logging, you can capture events such as connections, disconnections, queries, or tables queried.' +
"This is a granular rule that returns individual findings that can be suppressed with 'appliesTo'. The findings are in the format 'LogExport::<log>' for exported logs. Example: appliesTo: ['LogExport::audit'].",
level: NagMessageLevel.ERROR,
rule: RDSLoggingEnabled,
node: node,
Expand Down
3 changes: 2 additions & 1 deletion src/packs/nist-800-53-r4.ts
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,8 @@ export class NIST80053R4Checks extends NagPack {
this.applyRule({
info: 'The RDS DB instance does not have all CloudWatch log types exported - (Control IDs: AC-2(4), AC-2(g), AU-2(a)(d), AU-3, AU-12(a)(c)).',
explanation:
'To help with logging and monitoring within your environment, ensure Amazon Relational Database Service (Amazon RDS) logging is enabled. With Amazon RDS logging, you can capture events such as connections, disconnections, queries, or tables queried.',
'To help with logging and monitoring within your environment, ensure Amazon Relational Database Service (Amazon RDS) logging is enabled. With Amazon RDS logging, you can capture events such as connections, disconnections, queries, or tables queried.' +
"This is a granular rule that returns individual findings that can be suppressed with 'appliesTo'. The findings are in the format 'LogExport::<log>' for exported logs. Example: appliesTo: ['LogExport::audit'].",
level: NagMessageLevel.ERROR,
rule: RDSLoggingEnabled,
node: node,
Expand Down
3 changes: 2 additions & 1 deletion src/packs/nist-800-53-r5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,8 @@ export class NIST80053R5Checks extends NagPack {
this.applyRule({
info: 'The RDS DB Instance does not have all CloudWatch log types exported - (Control IDs: AC-2(4), AC-3(1), AC-3(10), AC-4(26), AC-6(9), AU-2b, AU-3a, AU-3b, AU-3c, AU-3d, AU-3e, AU-3f, AU-6(3), AU-6(4), AU-6(6), AU-6(9), AU-8b, AU-10, AU-12a, AU-12c, AU-12(1), AU-12(2), AU-12(3), AU-12(4), AU-14a, AU-14b, AU-14b, AU-14(3), CA-7b, CM-5(1)(b), IA-3(3)(b), MA-4(1)(a), PM-14a.1, PM-14b, PM-31, SC-7(9)(b), SI-1(1)(c), SI-3(8)(b), SI-4(2), SI-4(17), SI-4(20), SI-7(8), SI-10(1)(c)).',
explanation:
'To help with logging and monitoring within your environment, ensure Amazon Relational Database Service (Amazon RDS) logging is enabled. With Amazon RDS logging, you can capture events such as connections, disconnections, queries, or tables queried.',
'To help with logging and monitoring within your environment, ensure Amazon Relational Database Service (Amazon RDS) logging is enabled. With Amazon RDS logging, you can capture events such as connections, disconnections, queries, or tables queried.' +
"This is a granular rule that returns individual findings that can be suppressed with 'appliesTo'. The findings are in the format 'LogExport::<log>' for exported logs. Example: appliesTo: ['LogExport::audit'].",
level: NagMessageLevel.ERROR,
rule: RDSLoggingEnabled,
node: node,
Expand Down
3 changes: 2 additions & 1 deletion src/packs/pci-dss-321.ts
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,8 @@ export class PCIDSS321Checks extends NagPack {
this.applyRule({
info: 'The RDS DB Instance does not have all CloudWatch log types exported - (Control IDs: 10.1, 10.2.1, 10.2.2, 10.2.3, 10.2.4, 10.2.5, 10.3.1, 10.3.2, 10.3.3, 10.3.4, 10.3.5, 10.3.6).',
explanation:
'To help with logging and monitoring within your environment, ensure Amazon Relational Database Service (Amazon RDS) logging is enabled. With Amazon RDS logging, you can capture events such as connections, disconnections, queries, or tables queried.',
'To help with logging and monitoring within your environment, ensure Amazon Relational Database Service (Amazon RDS) logging is enabled. With Amazon RDS logging, you can capture events such as connections, disconnections, queries, or tables queried.' +
"This is a granular rule that returns individual findings that can be suppressed with 'appliesTo'. The findings are in the format 'LogExport::<log>' for exported logs. Example: appliesTo: ['LogExport::audit'].",
level: NagMessageLevel.ERROR,
rule: RDSLoggingEnabled,
node: node,
Expand Down
22 changes: 11 additions & 11 deletions src/rules/documentdb/DocumentDBClusterLogExports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,25 @@ SPDX-License-Identifier: Apache-2.0
import { parse } from 'path';
import { CfnResource } from 'aws-cdk-lib';
import { CfnDBCluster } from 'aws-cdk-lib/aws-docdb';
import { NagRuleCompliance } from '../../nag-rules';
import {
NagRuleCompliance,
NagRuleFindings,
NagRuleResult,
} from '../../nag-rules';

/**
* Document DB clusters have authenticate, createIndex, and dropCollection Log Exports enabled
* @param node the CfnResource to check
*/
export default Object.defineProperty(
(node: CfnResource): NagRuleCompliance => {
(node: CfnResource): NagRuleResult => {
if (node instanceof CfnDBCluster) {
if (node.enableCloudwatchLogsExports == undefined) {
return NagRuleCompliance.NON_COMPLIANT;
}
const needed = ['authenticate', 'createIndex', 'dropCollection'];
const exports = node.enableCloudwatchLogsExports;
const compliant = needed.every((i) => exports.includes(i));
if (compliant !== true) {
return NagRuleCompliance.NON_COMPLIANT;
}
return NagRuleCompliance.COMPLIANT;
const exports = node.enableCloudwatchLogsExports ?? [];
const findings: NagRuleFindings = needed
.filter((log) => !exports.includes(log))
.map((log) => `LogExport::${log}`);
return findings.length ? findings : NagRuleCompliance.COMPLIANT;
} else {
return NagRuleCompliance.NOT_APPLICABLE;
}
Expand Down
42 changes: 14 additions & 28 deletions src/rules/eks/EKSClusterControlPlaneLogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,53 +5,40 @@ SPDX-License-Identifier: Apache-2.0
import { parse } from 'path';
import { CfnResource, Stack } from 'aws-cdk-lib';
import { CfnCluster } from 'aws-cdk-lib/aws-eks';
import { NagRuleCompliance, NagRules } from '../../nag-rules';
import { NagRuleCompliance, NagRuleResult, NagRules } from '../../nag-rules';

/**
* EKS Clusters publish 'api', 'audit', 'authenticator, 'controllerManager', and 'scheduler' control plane logs
* @param node the CfnResource to check
*/
export default Object.defineProperty(
(node: CfnResource): NagRuleCompliance => {
(node: CfnResource): NagRuleResult => {
if (node instanceof CfnCluster) {
const logging = Stack.of(node).resolve(node.logging);
if (logging === undefined) {
return NagRuleCompliance.NON_COMPLIANT;
}
const clusterLogging = Stack.of(node).resolve(logging.clusterLogging);
if (clusterLogging === undefined) {
return NagRuleCompliance.NON_COMPLIANT;
}
const enabledTypes = Stack.of(node).resolve(clusterLogging.enabledTypes);
if (!Array.isArray(enabledTypes)) {
return NagRuleCompliance.NON_COMPLIANT;
}
const requiredTypes = new Set([
'api',
'audit',
'authenticator',
'controllerManager',
'scheduler',
]);
const logging = Stack.of(node).resolve(node.logging);
const clusterLogging = Stack.of(node).resolve(logging?.clusterLogging);
const enabledTypes: CfnCluster.LoggingTypeConfigProperty[] =
Stack.of(node).resolve(clusterLogging?.enabledTypes) ?? [];
for (const enabled of enabledTypes) {
requiredTypes.delete(NagRules.resolveIfPrimitive(node, enabled.type));
if (requiredTypes.size === 0) {
break;
}
}
if (requiredTypes.size !== 0) {
return NagRuleCompliance.NON_COMPLIANT;
}
return NagRuleCompliance.COMPLIANT;
return requiredTypes.size
? [...requiredTypes].map((log) => `LogExport::${log}`)
: NagRuleCompliance.COMPLIANT;
} else if (node.cfnResourceType === 'Custom::AWSCDK-EKS-Cluster') {
// The CDK uses a Custom Resource with AWS SDK calls to create EKS Clusters
const props = Stack.of(node).resolve((<any>node)._cfnProperties);
const clusterLogging = Stack.of(node).resolve(
props?.Config?.logging?.clusterLogging
);
if (!Array.isArray(clusterLogging)) {
return NagRuleCompliance.NON_COMPLIANT;
}
const clusterLogging =
Stack.of(node).resolve(props?.Config?.logging?.clusterLogging) ?? [];
const requiredTypes = new Set([
'api',
'audit',
Expand All @@ -69,10 +56,9 @@ export default Object.defineProperty(
}
}
}
if (requiredTypes.size !== 0) {
return NagRuleCompliance.NON_COMPLIANT;
}
return NagRuleCompliance.COMPLIANT;
return requiredTypes.size
? [...requiredTypes].map((log) => `LogExport::${log}`)
: NagRuleCompliance.COMPLIANT;
} else {
return NagRuleCompliance.NOT_APPLICABLE;
}
Expand Down
29 changes: 13 additions & 16 deletions src/rules/opensearch/OpenSearchSlowLogsToCloudWatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,33 @@ import { parse } from 'path';
import { CfnResource, Stack } from 'aws-cdk-lib';
import { CfnDomain as LegacyCfnDomain } from 'aws-cdk-lib/aws-elasticsearch';
import { CfnDomain } from 'aws-cdk-lib/aws-opensearchservice';
import { NagRuleCompliance, NagRules } from '../../nag-rules';
import {
NagRuleCompliance,
NagRuleFindings,
NagRuleResult,
NagRules,
} from '../../nag-rules';

/**
* OpenSearch Service domains minimally publish SEARCH_SLOW_LOGS and INDEX_SLOW_LOGS to CloudWatch Logs
* @param node the CfnResource to check
*/
export default Object.defineProperty(
(node: CfnResource): NagRuleCompliance => {
(node: CfnResource): NagRuleResult => {
if (node instanceof LegacyCfnDomain || node instanceof CfnDomain) {
const logPublishingOptions = Stack.of(node).resolve(
node.logPublishingOptions
);
if (logPublishingOptions == undefined) {
return NagRuleCompliance.NON_COMPLIANT;
}
const requiredSlowLogs = [
logPublishingOptions?.SEARCH_SLOW_LOGS,
logPublishingOptions?.INDEX_SLOW_LOGS,
];
const requiredSlowLogs = ['SEARCH_SLOW_LOGS', 'INDEX_SLOW_LOGS'];
const findings: NagRuleFindings = [];
for (const log of requiredSlowLogs) {
const resolvedLog = Stack.of(node).resolve(log);
if (resolvedLog == undefined) {
return NagRuleCompliance.NON_COMPLIANT;
}
const enabled = NagRules.resolveIfPrimitive(node, resolvedLog.enabled);
const resolvedLog = Stack.of(node).resolve(logPublishingOptions?.[log]);
const enabled = NagRules.resolveIfPrimitive(node, resolvedLog?.enabled);
if (!enabled) {
return NagRuleCompliance.NON_COMPLIANT;
findings.push(`LogExport::${log}`);
}
}
return NagRuleCompliance.COMPLIANT;
return findings.length ? findings : NagRuleCompliance.COMPLIANT;
} else {
return NagRuleCompliance.NOT_APPLICABLE;
}
Expand Down
27 changes: 15 additions & 12 deletions src/rules/rds/AuroraMySQLLogging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,21 @@ Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
import { parse } from 'path';
import { CfnResource } from 'aws-cdk-lib';
import { CfnResource, Stack } from 'aws-cdk-lib';
import { CfnDBCluster } from 'aws-cdk-lib/aws-rds';
import { NagRuleCompliance, NagRules } from '../../nag-rules';
import {
NagRuleCompliance,
NagRuleFindings,
NagRuleResult,
NagRules,
} from '../../nag-rules';

/**
* RDS Aurora MySQL serverless clusters have audit, error, general, and slowquery Log Exports enabled
* @param node the CfnResource to check
*/
export default Object.defineProperty(
(node: CfnResource): NagRuleCompliance => {
(node: CfnResource): NagRuleResult => {
if (node instanceof CfnDBCluster) {
const engine = NagRules.resolveIfPrimitive(
node,
Expand All @@ -25,16 +30,14 @@ export default Object.defineProperty(
(engine.toLowerCase() == 'aurora' ||
engine.toLowerCase() == 'aurora-mysql')
) {
if (node.enableCloudwatchLogsExports == undefined) {
return NagRuleCompliance.NON_COMPLIANT;
}
const exports =
Stack.of(node).resolve(node.enableCloudwatchLogsExports) ?? [];
const needed = ['audit', 'error', 'general', 'slowquery'];
const exports = node.enableCloudwatchLogsExports.map((i) => {
return i.toLowerCase();
});
const compliant = needed.every((i) => exports.includes(i));
if (compliant !== true) {
return NagRuleCompliance.NON_COMPLIANT;
const findings: NagRuleFindings = needed
.filter((log) => !exports.includes(log))
.map((log) => `LogExport::${log}`);
if (findings.length) {
return findings;
}
}
return NagRuleCompliance.COMPLIANT;
Expand Down
Loading

0 comments on commit d737655

Please sign in to comment.