cdk-nag
Version:
Check CDK v2 applications for best practices using a combination on available rule packs.
838 lines • 203 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AwsSolutionsChecks = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
const aws_cdk_lib_1 = require("aws-cdk-lib");
const nag_pack_1 = require("../nag-pack");
const nag_rules_1 = require("../nag-rules");
const apigw_1 = require("../rules/apigw");
const appsync_1 = require("../rules/appsync");
const autoscaling_1 = require("../rules/autoscaling");
const cloud9_1 = require("../rules/cloud9");
const cloudfront_1 = require("../rules/cloudfront");
const codebuild_1 = require("../rules/codebuild");
const cognito_1 = require("../rules/cognito");
const documentdb_1 = require("../rules/documentdb");
const dynamodb_1 = require("../rules/dynamodb");
const ec2_1 = require("../rules/ec2");
const ecr_1 = require("../rules/ecr");
const ecs_1 = require("../rules/ecs");
const efs_1 = require("../rules/efs");
const eks_1 = require("../rules/eks");
const elasticache_1 = require("../rules/elasticache");
const elasticbeanstalk_1 = require("../rules/elasticbeanstalk");
const elb_1 = require("../rules/elb");
const emr_1 = require("../rules/emr");
const eventbridge_1 = require("../rules/eventbridge");
const glue_1 = require("../rules/glue");
const iam_1 = require("../rules/iam");
const kinesis_1 = require("../rules/kinesis");
const kms_1 = require("../rules/kms");
const lambda_1 = require("../rules/lambda");
const lex_1 = require("../rules/lex");
const mediastore_1 = require("../rules/mediastore");
const msk_1 = require("../rules/msk");
const neptune_1 = require("../rules/neptune");
const opensearch_1 = require("../rules/opensearch");
const quicksight_1 = require("../rules/quicksight");
const rds_1 = require("../rules/rds");
const redshift_1 = require("../rules/redshift");
const s3_1 = require("../rules/s3");
const sagemaker_1 = require("../rules/sagemaker");
const secretsmanager_1 = require("../rules/secretsmanager");
const sns_1 = require("../rules/sns");
const sqs_1 = require("../rules/sqs");
const stepfunctions_1 = require("../rules/stepfunctions");
const timestream_1 = require("../rules/timestream");
const vpc_1 = require("../rules/vpc");
/**
* Check Best practices based on AWS Solutions Security Matrix
*
*/
class AwsSolutionsChecks extends nag_pack_1.NagPack {
constructor(props) {
super(props);
this.packName = 'AwsSolutions';
}
visit(node) {
if (node instanceof aws_cdk_lib_1.CfnResource) {
this.checkCompute(node);
this.checkStorage(node);
this.checkDatabases(node);
this.checkNetworkDelivery(node);
this.checkManagementGovernance(node);
this.checkMachineLearning(node);
this.checkAnalytics(node);
this.checkSecurityCompliance(node);
this.checkServerless(node);
this.checkApplicationIntegration(node);
this.checkMediaServices(node);
this.checkDeveloperTools(node);
this.checkLambda(node);
}
}
/**
* Check Compute Services
* @param node the CfnResource to check
* @param ignores list of ignores for the resource
*/
checkCompute(node) {
this.applyRule({
ruleSuffixOverride: 'EB1',
info: 'The Elastic Beanstalk environment is not configured to use a specific VPC.',
explanation: 'Use a non-default VPC in order to separate your environment from default resources.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: elasticbeanstalk_1.ElasticBeanstalkVPCSpecified,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'EB3',
info: 'The Elastic Beanstalk environment does not have managed updates enabled.',
explanation: 'Enable managed platform updates for beanstalk environments in order to receive bug fixes, software updates and new features. Managed platform updates perform immutable environment updates.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: elasticbeanstalk_1.ElasticBeanstalkManagedUpdatesEnabled,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'EB4',
info: 'The Elastic Beanstalk environment does not upload EC2 Instance logs to S3.',
explanation: 'Beanstalk environment logs should be retained and uploaded to Amazon S3 in order to keep the logging data for future audits, historical purposes or to track and analyze the EB application environment behavior for a long period of time.',
level: nag_rules_1.NagMessageLevel.WARN,
rule: elasticbeanstalk_1.ElasticBeanstalkEC2InstanceLogsToS3,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'EC23',
info: 'The Security Group allows for 0.0.0.0/0 or ::/0 inbound access.',
explanation: 'Large port ranges, when open, expose instances to unwanted attacks. More than that, they make traceability of vulnerabilities very difficult. For instance, your web servers may only require 80 and 443 ports to be open, but not all. One of the most common mistakes observed is when all ports for 0.0.0.0/0 range are open in a rush to access the instance. EC2 instances must expose only to those ports enabled on the corresponding security group level.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: ec2_1.EC2RestrictedInbound,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'EC26',
info: 'The resource creates one or more EBS volumes that have encryption disabled.',
explanation: "With EBS encryption, you aren't required to build, maintain, and secure your own key management infrastructure. EBS encryption uses KMS keys when creating encrypted volumes and snapshots. This helps protect data at rest.",
level: nag_rules_1.NagMessageLevel.ERROR,
rule: ec2_1.EC2EBSVolumeEncrypted,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'EC27',
info: 'The Security Group does not have a description.',
explanation: 'Descriptions help simplify operations and remove any opportunities for operator errors.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: ec2_1.EC2SecurityGroupDescription,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'EC28',
info: 'The EC2 instance/AutoScaling launch configuration does not have detailed monitoring enabled.',
explanation: 'Monitoring data helps make better decisions on architecting and managing compute resources.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: ec2_1.EC2InstanceDetailedMonitoringEnabled,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'EC29',
info: 'The EC2 instance is not part of an ASG and has Termination Protection disabled.',
explanation: 'Termination Protection safety feature enabled in order to protect the instances from being accidentally terminated.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: ec2_1.EC2InstanceTerminationProtection,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'ECR1',
info: 'The ECR Repository allows open access.',
explanation: 'Removing * principals in an ECR Repository helps protect against unauthorized access.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: ecr_1.ECROpenAccess,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'ECS2',
info: 'The ECS Task Definition includes a container definition that directly specifies environment variables.',
explanation: 'Use secrets to inject environment variables during container startup from AWS Systems Manager Parameter Store or Secrets Manager instead of directly specifying plaintext environment variables. Updates to direct environment variables require operators to change task definitions and perform new deployments.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: ecs_1.ECSTaskDefinitionNoEnvironmentVariables,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'ECS4',
info: 'The ECS Cluster has CloudWatch Container Insights disabled.',
explanation: 'CloudWatch Container Insights allow operators to gain a better perspective on how the cluster’s applications and microservices are performing.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: ecs_1.ECSClusterCloudWatchContainerInsights,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'ECS7',
info: 'One or more containers in the ECS Task Definition do not have container logging enabled.',
explanation: "Container logging allows operators to view and aggregate the logs from the container. Containers should use the 'awslogs' driver at a minimum.",
level: nag_rules_1.NagMessageLevel.ERROR,
rule: ecs_1.ECSTaskDefinitionContainerLogging,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'EKS1',
info: "The EKS cluster's Kubernetes API server endpoint has public access enabled.",
explanation: "A cluster's Kubernetes API server endpoint should not be publicly accessible from the Internet in order to avoid exposing private data and minimizing security risks. The API server endpoints should only be accessible from within a AWS Virtual Private Cloud (VPC).",
level: nag_rules_1.NagMessageLevel.ERROR,
rule: eks_1.EKSClusterNoEndpointPublicAccess,
node: node,
});
this.applyRule({
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.' +
"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: nag_rules_1.NagMessageLevel.ERROR,
rule: eks_1.EKSClusterControlPlaneLogs,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'ELB1',
info: 'The CLB is used for incoming HTTP/HTTPS traffic. Use ALBs instead.',
explanation: 'HTTP/HTTPS applications (monolithic or containerized) should use the ALB instead of the CLB for enhanced incoming traffic distribution, better performance and lower costs.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: elb_1.CLBNoInboundHttpHttps,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'ELB2',
info: 'The ELB does not have access logs enabled.',
explanation: 'Access logs allow operators to analyze traffic patterns and identify and troubleshoot security issues.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: elb_1.ELBLoggingEnabled,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'ELB3',
info: 'The CLB does not have connection draining enabled.',
explanation: 'With Connection Draining feature enabled, if an EC2 backend instance fails health checks The CLB will not send any new requests to the unhealthy instance. However, it will still allow existing (in-flight) requests to complete for the duration of the configured timeout.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: elb_1.CLBConnectionDraining,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'ELB4',
info: 'The CLB does not use at least two AZs with the Cross-Zone Load Balancing feature enabled.',
explanation: 'CLBs can distribute the traffic evenly across all backend instances. To use Cross-Zone Load Balancing at optimal level, the system should maintain an equal EC2 capacity distribution in each of the AZs registered with the load balancer.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: elb_1.ELBCrossZoneLoadBalancingEnabled,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'ELB5',
info: 'The CLB listener is not configured for secure (HTTPs or SSL) protocols for client communication.',
explanation: 'The HTTPs or SSL protocols enable secure communication by encrypting the communication between the client and the load balancer.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: elb_1.ELBTlsHttpsListenersOnly,
node: node,
});
}
/**
* Check Storage Services
* @param node the CfnResource to check
* @param ignores list of ignores for the resource
*/
checkStorage(node) {
this.applyRule({
ruleSuffixOverride: 'S1',
info: 'The S3 Bucket has server access logs disabled.',
explanation: 'The bucket should have server access logging enabled to provide detailed records for the requests that are made to the bucket.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: s3_1.S3BucketLoggingEnabled,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'S2',
info: 'The S3 Bucket does not have public access restricted and blocked.',
explanation: 'The bucket should have public access restricted and blocked to prevent unauthorized access.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: s3_1.S3BucketLevelPublicAccessProhibited,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'S5',
info: 'The S3 static website bucket either has an open world bucket policy or does not use a CloudFront Origin Access Identity (OAI) in the bucket policy for limited getObject and/or putObject permissions.',
explanation: 'An OAI allows you to provide access to content in your S3 static website bucket through CloudFront URLs without enabling public access through an open bucket policy, disabling S3 Block Public Access settings, and/or through object ACLs.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: s3_1.S3WebBucketOAIAccess,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'S10',
info: 'The S3 Bucket or bucket policy does not require requests to use SSL.',
explanation: 'You can use HTTPS (TLS) to help prevent potential attackers from eavesdropping on or manipulating network traffic using person-in-the-middle or similar attacks. You should allow only encrypted connections over HTTPS (TLS) using the aws:SecureTransport condition on Amazon S3 bucket policies.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: s3_1.S3BucketSSLRequestsOnly,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'EFS1',
info: 'The EFS is not configured for encryption at rest.',
explanation: 'By using an encrypted file system, data and metadata are automatically encrypted before being written to the file system. Similarly, as data and metadata are read, they are automatically decrypted before being presented to the application. These processes are handled transparently by EFS without requiring modification of applications.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: efs_1.EFSEncrypted,
node: node,
});
}
/**
* Check Database Services
* @param node the CfnResource to check
* @param ignores list of ignores for the resource
*/
checkDatabases(node) {
this.applyRule({
ruleSuffixOverride: 'RDS2',
info: 'The RDS instance or Aurora DB cluster does not have storage encryption enabled.',
explanation: 'Storage encryption helps protect data-at-rest by encrypting the underlying storage, automated backups, read replicas, and snapshots for the database.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: rds_1.RDSStorageEncrypted,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RDS3',
info: 'The non-Aurora RDS DB instance does not have multi-AZ support enabled.',
explanation: 'Use multi-AZ deployment configurations for high availability and automatic failover support fully managed by AWS.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: rds_1.RDSMultiAZSupport,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RDS6',
info: 'The RDS Aurora MySQL/PostgresSQL cluster does not have IAM Database Authentication enabled.',
explanation: "With IAM Database Authentication enabled, the system doesn't have to use a password when connecting to the MySQL/PostgreSQL database instances, instead it uses an authentication token.",
level: nag_rules_1.NagMessageLevel.ERROR,
rule: rds_1.AuroraMySQLPostgresIAMAuth,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RDS8',
info: 'The RDS DB Security Group allows for 0.0.0.0/0 inbound access.',
explanation: 'RDS DB security groups should not allow access from 0.0.0.0/0 (i.e. anywhere, every machine that has the ability to establish a connection) in order to reduce the risk of unauthorized access.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: rds_1.RDSRestrictedInbound,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RDS10',
info: 'The RDS instance or Aurora DB cluster does not have deletion protection enabled.',
explanation: 'Enabling Deletion Protection at the cluster level for Amazon Aurora databases or instance level for non Aurora instances helps protect from accidental deletion.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: rds_1.RDSInstanceDeletionProtectionEnabled,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RDS11',
info: 'The RDS instance or Aurora DB cluster uses the default endpoint port.',
explanation: 'Port obfuscation (using a non default endpoint port) adds an additional layer of defense against non-targeted attacks (i.e. MySQL/Aurora port 3306, SQL Server port 1433, PostgreSQL port 5432, etc).',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: rds_1.RDSNonDefaultPort,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RDS13',
info: 'The RDS instance is not configured for automated backups.',
explanation: 'Automated backups allow for point-in-time recovery.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: rds_1.RDSInstanceBackupEnabled,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RDS14',
info: 'The RDS Aurora MySQL cluster does not have Backtrack enabled.',
explanation: 'Backtrack helps order to rewind cluster tables to a specific time, without using backups.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: rds_1.AuroraMySQLBacktrack,
node: node,
});
this.applyRule({
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 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: nag_rules_1.NagMessageLevel.ERROR,
rule: rds_1.AuroraMySQLLogging,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'DDB3',
info: 'The DynamoDB table does not have Point-in-time Recovery enabled.',
explanation: 'DynamoDB continuous backups represent an additional layer of insurance against accidental loss of data on top of on-demand backups. The DynamoDB service can back up the data with per-second granularity and restore it to any single second from the time PITR was enabled up to the prior 35 days.',
level: nag_rules_1.NagMessageLevel.WARN,
rule: dynamodb_1.DynamoDBPITREnabled,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'DDB4',
info: 'The DAX cluster does not have server-side encryption enabled.',
explanation: 'Data in cache, configuration data and log files should be encrypted using Server-Side Encryption in order to protect from unauthorized access to the underlying storage.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: dynamodb_1.DAXEncrypted,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'AEC1',
info: 'The ElastiCache cluster is not provisioned in a VPC.',
explanation: 'Provisioning the cluster within a VPC allows for better flexibility and control over the cache clusters security, availability, traffic routing and more.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: elasticache_1.ElastiCacheClusterInVPC,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'AEC3',
info: 'The ElastiCache Redis cluster does not have both encryption in transit and at rest enabled.',
explanation: 'Encryption in transit helps secure communications to the cluster. Encryption at rest helps protect data at rest from unauthorized access.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: elasticache_1.ElastiCacheRedisClusterEncryption,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'AEC4',
info: 'The ElastiCache Redis cluster is not deployed in a Multi-AZ configuration.',
explanation: 'The cluster should use a Multi-AZ deployment configuration for high availability.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: elasticache_1.ElastiCacheRedisClusterMultiAZ,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'AEC5',
info: 'The ElastiCache cluster uses the default endpoint port.',
explanation: 'Port obfuscation (using a non default endpoint port) adds an additional layer of defense against non-targeted attacks (i.e. Redis port 6379 and Memcached port 11211).',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: elasticache_1.ElastiCacheClusterNonDefaultPort,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'AEC6',
info: 'The ElastiCache Redis cluster does not use Redis AUTH for user authentication.',
explanation: 'Redis authentication tokens enable Redis to require a token (password) before allowing clients to execute commands, thereby improving data security.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: elasticache_1.ElastiCacheRedisClusterRedisAuth,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'N1',
info: 'The Neptune DB cluster is not deployed in a Multi-AZ configuration.',
explanation: 'The cluster should use a Multi-AZ deployment configuration for high availability.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: neptune_1.NeptuneClusterMultiAZ,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'N2',
info: 'The Neptune DB instance does not have Auto Minor Version Upgrade enabled.',
explanation: 'The Neptune service regularly releases engine updates. Enabling Auto Minor Version Upgrade will allow the service to automatically apply these upgrades to DB Instances.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: neptune_1.NeptuneClusterAutomaticMinorVersionUpgrade,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'N3',
info: 'The Neptune DB cluster does not have a reasonable minimum backup retention period configured.',
explanation: 'The retention period represents the number of days to retain automated snapshots. A minimum retention period of 7 days is recommended but can be adjust to meet system requirements.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: neptune_1.NeptuneClusterBackupRetentionPeriod,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'N4',
info: 'The Neptune DB cluster does not have encryption at rest enabled.',
explanation: 'Encrypting data-at-rest protects data confidentiality and prevents unauthorized users from accessing sensitive information.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: neptune_1.NeptuneClusterEncryptionAtRest,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'N5',
info: 'The Neptune DB cluster does not have IAM Database Authentication enabled.',
explanation: "With IAM Database Authentication enabled, the system doesn't have to use a password when connecting to the cluster.",
level: nag_rules_1.NagMessageLevel.ERROR,
rule: neptune_1.NeptuneClusterIAMAuth,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RS1',
info: 'The Redshift cluster does not require TLS/SSL encryption.',
explanation: 'Enabling the "require_ssl" parameter secures data-in-transit by encrypting the connection between the clients and the Redshift clusters.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: redshift_1.RedshiftRequireTlsSSL,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RS2',
info: 'The Redshift cluster is not provisioned in a VPC.',
explanation: 'Provisioning the cluster within a VPC allows for better flexibility and control over the Redshift clusters security, availability, traffic routing and more.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: redshift_1.RedshiftClusterInVPC,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RS3',
info: 'The Redshift cluster uses the default "awsuser" username.',
explanation: 'Using a custom master user name instead of the default master user name (i.e. "awsuser") provides an additional layer of defense against non-targeted attacks.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: redshift_1.RedshiftClusterNonDefaultUsername,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RS4',
info: 'The Redshift cluster uses the default endpoint port.',
explanation: 'Port obfuscation (using a non default endpoint port) adds an additional layer of defense against non-targeted attacks (i.e. Redshift port 5439).',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: redshift_1.RedshiftClusterNonDefaultPort,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RS5',
info: 'The Redshift cluster does not have audit logging enabled.',
explanation: 'Audit logging helps operators troubleshoot issues and ensure security.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: redshift_1.RedshiftClusterAuditLogging,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RS6',
info: 'The Redshift cluster does not have encryption at rest enabled.',
explanation: 'Encrypting data-at-rest protects data confidentiality.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: redshift_1.RedshiftClusterEncryptionAtRest,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RS8',
info: 'The Redshift cluster is publicly accessible.',
explanation: 'Disabling public accessibility helps minimize security risks.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: redshift_1.RedshiftClusterPublicAccess,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RS9',
info: 'The Redshift cluster does not have version upgrade enabled.',
explanation: 'Version Upgrade must enabled to enable the cluster to automatically receive upgrades during the maintenance window.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: redshift_1.RedshiftClusterVersionUpgrade,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RS10',
info: 'The Redshift cluster does not have a retention period for automated snapshots configured.',
explanation: 'The retention period represents the number of days to retain automated snapshots. A positive retention period should be set to configure this feature.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: redshift_1.RedshiftBackupEnabled,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'RS11',
info: 'The Redshift cluster does not have user activity logging enabled.',
explanation: 'User activity logging logs each query before it is performed on the clusters database. To enable this feature associate a Redshift Cluster Parameter Group with the "enable_user_activity_logging" parameter set to "true".',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: redshift_1.RedshiftClusterUserActivityLogging,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'DOC1',
info: 'The Document DB cluster does not have encryption at rest enabled.',
explanation: 'Encrypting data-at-rest protects data confidentiality and prevents unauthorized users from accessing sensitive information.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: documentdb_1.DocumentDBClusterEncryptionAtRest,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'DOC2',
info: 'The Document DB cluster uses the default endpoint port.',
explanation: 'Port obfuscation (using a non default endpoint port) adds an additional layer of defense against non-targeted attacks (i.e. MongoDB port 27017).',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: documentdb_1.DocumentDBClusterNonDefaultPort,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'DOC3',
info: 'The Document DB cluster does not have the username and password stored in Secrets Manager.',
explanation: "Secrets Manager enables operators to replace hardcoded credentials in your code, including passwords, with an API call to Secrets Manager to retrieve the secret programmatically. This helps ensure the secret can't be compromised by someone examining system code, because the secret no longer exists in the code. Also, operators can configure Secrets Manager to automatically rotate the secret for you according to a specified schedule. This enables you to replace long-term secrets with short-term ones, significantly reducing the risk of compromise.",
level: nag_rules_1.NagMessageLevel.ERROR,
rule: documentdb_1.DocumentDBCredentialsInSecretsManager,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'DOC4',
info: 'The Document DB cluster does not have a reasonable minimum backup retention period configured.',
explanation: 'The retention period represents the number of days to retain automated snapshots. A minimum retention period of 7 days is recommended but can be adjust to meet system requirements.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: documentdb_1.DocumentDBClusterBackupRetentionPeriod,
node: node,
});
this.applyRule({
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 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: nag_rules_1.NagMessageLevel.ERROR,
rule: documentdb_1.DocumentDBClusterLogExports,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'TS3',
info: 'The Timestream database does not use a Customer Managed KMS Key for at rest encryption.',
explanation: 'All Timestream tables in a database are encrypted at rest by default using AWS Managed Key. These keys are rotated every three years. Data at rest must be encrypted using CMKs if you require more control over the permissions and lifecycle of your keys, including the ability to have them automatically rotated on an annual basis.',
level: nag_rules_1.NagMessageLevel.WARN,
rule: timestream_1.TimestreamDatabaseCustomerManagedKey,
node: node,
});
}
/**
* Check Network and Delivery Services
* @param node the CfnResource to check
* @param ignores list of ignores for the resource
*/
checkNetworkDelivery(node) {
this.applyRule({
ruleSuffixOverride: 'VPC3',
info: 'A Network ACL or Network ACL entry has been implemented.',
explanation: 'Network ACLs should be used sparingly for the following reasons: they can be complex to manage, they are stateless, every IP address must be explicitly opened in each (inbound/outbound) direction, and they affect a complete subnet. Use security groups when possible as they are stateful and easier to manage.',
level: nag_rules_1.NagMessageLevel.WARN,
rule: vpc_1.VPCNoNACLs,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'VPC7',
info: 'The VPC does not have an associated Flow Log.',
explanation: 'VPC Flow Logs capture network flow information for a VPC, subnet, or network interface and stores it in Amazon CloudWatch Logs. Flow log data can help customers troubleshoot network issues; for example, to diagnose why specific traffic is not reaching an instance, which might be a result of overly restrictive security group rules.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: vpc_1.VPCFlowLogsEnabled,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'CFR1',
info: 'The CloudFront distribution may require Geo restrictions.',
explanation: 'Geo restriction may need to be enabled for the distribution in order to allow or deny a country in order to allow or restrict users in specific locations from accessing content.',
level: nag_rules_1.NagMessageLevel.WARN,
rule: cloudfront_1.CloudFrontDistributionGeoRestrictions,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'CFR2',
info: 'The CloudFront distribution may require integration with AWS WAF.',
explanation: 'The Web Application Firewall can help protect against application-layer attacks that can compromise the security of the system or place unnecessary load on them.',
level: nag_rules_1.NagMessageLevel.WARN,
rule: cloudfront_1.CloudFrontDistributionWAFIntegration,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'CFR3',
info: 'The CloudFront distribution does not have access logging enabled.',
explanation: 'Enabling access logs helps operators track all viewer requests for the content delivered through the Content Delivery Network.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: cloudfront_1.CloudFrontDistributionAccessLogging,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'CFR4',
info: 'The CloudFront distribution allows for SSLv3 or TLSv1 for HTTPS viewer connections.',
explanation: "Vulnerabilities have been and continue to be discovered in the deprecated SSL and TLS protocols. Help protect viewer connections by specifying a viewer certificate that enforces a minimum of TLSv1.1 or TLSv1.2 in the security policy. Distributions that use the default CloudFront viewer certificate or use 'vip' for the 'SslSupportMethod' are non-compliant with this rule, as the minimum security policy is set to TLSv1 regardless of the specified 'MinimumProtocolVersion'.",
level: nag_rules_1.NagMessageLevel.ERROR,
rule: cloudfront_1.CloudFrontDistributionHttpsViewerNoOutdatedSSL,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'CFR5',
info: 'The CloudFront distributions uses SSLv3 or TLSv1 for communication to the origin.',
explanation: 'Vulnerabilities have been and continue to be discovered in the deprecated SSL and TLS protocols. Using a security policy with minimum TLSv1.1 or TLSv1.2 and appropriate security ciphers for HTTPS helps protect viewer connections.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: cloudfront_1.CloudFrontDistributionNoOutdatedSSL,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'CFR6',
info: 'The CloudFront Streaming distribution does not use an origin access identity with an S3 origin.',
explanation: 'Origin access identities help with security by restricting any direct access to objects through S3 URLs.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: cloudfront_1.CloudFrontDistributionS3OriginAccessIdentity,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'CFR7',
info: 'The CloudFront distribution does not use an origin access control with an S3 origin.',
explanation: 'Origin access controls help with security by restricting any direct access to objects through S3 URLs.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: cloudfront_1.CloudFrontDistributionS3OriginAccessControl,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'APIG1',
info: 'The API does not have access logging enabled.',
explanation: 'Enabling access logs helps operators view who accessed an API and how the caller accessed the API.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: apigw_1.APIGWAccessLogging,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'APIG2',
info: 'The REST API does not have request validation enabled.',
explanation: 'The API should have basic request validation enabled. If the API is integrated with custom source (Lambda, ECS, etc..) in the backend, deeper input validation should be considered for implementation.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: apigw_1.APIGWRequestValidation,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'APIG3',
info: 'The REST API stage is not associated with AWS WAFv2 web ACL.',
explanation: 'AWS WAFv2 is a web application firewall that helps protect web applications and APIs from attacks by allowing configured rules to allow, block, or monitor (count) web requests based on customizable rules and conditions that are defined.',
level: nag_rules_1.NagMessageLevel.WARN,
rule: apigw_1.APIGWAssociatedWithWAF,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'APIG4',
info: 'The API does not implement authorization.',
explanation: 'In most cases an API needs to have an authentication and authorization implementation strategy. This includes using such approaches as IAM, Cognito User Pools, Custom authorizer, etc.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: apigw_1.APIGWAuthorization,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'APIG6',
info: 'The REST API Stage does not have CloudWatch logging enabled for all methods.',
explanation: 'Enabling CloudWatch logs at the stage level helps operators to track and analyze execution behavior at the API stage level.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: apigw_1.APIGWExecutionLoggingEnabled,
node: node,
});
}
/**
* Check Management and Governance Services
* @param node the CfnResource to check
* @param ignores list of ignores for the resource
*/
checkManagementGovernance(node) {
this.applyRule({
ruleSuffixOverride: 'AS1',
info: 'The Auto Scaling Group does not have a cooldown period.',
explanation: 'A cooldown period temporarily suspends any scaling activities in order to allow the newly launched EC2 instance(s) some time to start handling the application traffic.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: autoscaling_1.AutoScalingGroupCooldownPeriod,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'AS2',
info: 'The Auto Scaling Group does not have properly configured health checks.',
explanation: 'The health check feature enables the service to detect whether its registered EC2 instances are healthy or not.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: autoscaling_1.AutoScalingGroupHealthCheck,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'AS3',
info: 'The Auto Scaling Group does not have notifications configured for all scaling events.',
explanation: 'Notifications on EC2 instance launch, launch error, termination, and termination errors allow operators to gain better insights into systems attributes such as activity and health.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: autoscaling_1.AutoScalingGroupScalingNotifications,
node: node,
});
}
/**
* Check Machine Learning Services
* @param node the CfnResource to check
* @param ignores list of ignores for the resource
*/
checkMachineLearning(node) {
this.applyRule({
ruleSuffixOverride: 'LEX4',
info: 'Lex conversation logs are enabled and not encrypted with a KMS key.',
explanation: 'You can use encryption to help protect the contents of your conversation logs. For text and audio logs, you can use AWS KMS customer managed CMKs to encrypt data in your CloudWatch Logs log group and S3 bucket.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: lex_1.LexBotAliasEncryptedConversationLogs,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'SM1',
info: 'The SageMaker notebook instance is not provisioned inside a VPC.',
explanation: 'Provisioning the notebook instances inside a VPC enables the notebook to access VPC-only resources such as EFS file systems.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: sagemaker_1.SageMakerNotebookInVPC,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'SM2',
info: 'The SageMaker notebook instance does not have an encrypted storage volume.',
explanation: 'Encrypting storage volumes helps protect SageMaker data-at-rest.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: sagemaker_1.SageMakerNotebookInstanceKMSKeyConfigured,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'SM3',
info: 'The SageMaker notebook instance has direct internet access enabled.',
explanation: 'Disabling public accessibility helps minimize security risks.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: sagemaker_1.SageMakerNotebookNoDirectInternetAccess,
node: node,
});
}
/**
* Check Analytics Services
* @param node the CfnResource to check
* @param ignores list of ignores for the resource
*/
checkAnalytics(node) {
this.applyRule({
ruleSuffixOverride: 'EMR2',
info: 'The EMR cluster does not have S3 logging enabled.',
explanation: 'Uploading logs to S3 enables the system to keep the logging data for historical purposes or to track and analyze the clusters behavior.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: emr_1.EMRS3AccessLogging,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'EMR4',
info: 'The EMR cluster does not use a security configuration with local disk encryption enabled.',
explanation: 'Local disk encryption uses a combination of open-source HDFS encryption and LUKS encryption to secure data at rest.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: emr_1.EMRLocalDiskEncryption,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'EMR5',
info: 'The EMR cluster does not use a security configuration with encryption in transit enabled and configured.',
explanation: 'EMR Clusters should have a method for encrypting data in transit using Transport Layer Security (TLS).',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: emr_1.EMREncryptionInTransit,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'EMR6',
info: 'The EMR cluster does not implement authentication via an EC2 Key Pair or Kerberos.',
explanation: 'SSH clients can use an EC2 key pair to authenticate to cluster instances. Alternatively, with EMR release version 5.10.0 or later, solutions can configure Kerberos to authenticate users and SSH connections to the master node.',
level: nag_rules_1.NagMessageLevel.ERROR,
rule: emr_1.EMRAuthEC2KeyPairOrKerberos,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'GL1',
info: 'The Glue crawler or job does not use a security configuration with CloudWatch Log encryption enabled.',
explanation: 'Enabling encryption at rest helps prevent unauthorized users from getting access to the logging data published to CloudWatch Logs.',
level: nag_rules_1.NagMessageLevel.WARN,
rule: glue_1.GlueEncryptedCloudWatchLogs,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'GL3',
info: 'The Glue job does not use a security configuration with job bookmark encryption enabled.',
explanation: 'Job bookmark encryption encrypts bookmark data before it is sent to Amazon S3 for storage.',
level: nag_rules_1.NagMessageLevel.WARN,
rule: glue_1.GlueJobBookmarkEncrypted,
node: node,
});
this.applyRule({
ruleSuffixOverride: 'KDA3',
info: 'The Kinesis Data Analytics Flink Application does not have checkpointing enabled.',
explanation: 'Checkpoints are backups of application state that KDA automatically creates periodically and uses to restore from faults.',
level: n