diff --git a/API.md b/API.md index 40ee7d31c9..fd288c6f2d 100644 --- a/API.md +++ b/API.md @@ -9,6 +9,7 @@ Name|Description [HIPAASecurityChecks](#cdk-nag-hipaasecuritychecks)|Check for HIPAA Security compliance. [NIST80053R4Checks](#cdk-nag-nist80053r4checks)|Check for NIST 800-53 rev 4 compliance. [NIST80053R5Checks](#cdk-nag-nist80053r5checks)|Check for NIST 800-53 rev 5 compliance. +[NZISM36Checks](#cdk-nag-nzism36checks)|Check for NZISM v36-1022-20 compliance. [NagPack](#cdk-nag-nagpack)|Base class for all rule packs. [NagReportLogger](#cdk-nag-nagreportlogger)|A NagLogger that creates compliance reports. [NagRules](#cdk-nag-nagrules)|Helper class with methods for rule creation. @@ -412,12 +413,57 @@ visit(node: IConstruct): void +## class NZISM36Checks + +Check for NZISM v36-1022-20 compliance. + +Based on the NZISM v36-1022-20: + +__Implements__: [IAspect](#aws-cdk-lib-iaspect) +__Extends__: [NagPack](#cdk-nag-nagpack) + +### Initializer + + + + +```ts +new NZISM36Checks(props?: NagPackProps) +``` + +* **props** ([NagPackProps](#cdk-nag-nagpackprops)) *No description* + * **additionalLoggers** (Array<[INagLogger](#cdk-nag-inaglogger)>) Additional NagLoggers for logging rule validation outputs. __*Optional*__ + * **logIgnores** (boolean) Whether or not to log suppressed rule violations as informational messages (default: false). __*Optional*__ + * **reportFormats** (Array<[NagReportFormat](#cdk-nag-nagreportformat)>) If reports are enabled, the output formats of compliance reports in the App's output directory (default: only CSV). __*Optional*__ + * **reports** (boolean) Whether or not to generate compliance reports for applied Stacks in the App's output directory (default: true). __*Optional*__ + * **suppressionIgnoreCondition** ([INagSuppressionIgnore](#cdk-nag-inagsuppressionignore)) Conditionally prevent rules from being suppressed (default: no user provided condition). __*Optional*__ + * **verbose** (boolean) Whether or not to enable extended explanatory descriptions on warning, error, and logged ignore messages (default: false). __*Optional*__ + + +### Methods + + +#### visit(node) + +All aspects can visit an IConstruct. + +```ts +visit(node: IConstruct): void +``` + +* **node** ([IConstruct](#constructs-iconstruct)) *No description* + + + + + + ## class NagPack Base class for all rule packs. __Implements__: [IAspect](#aws-cdk-lib-iaspect) -__Implemented by__: [AwsSolutionsChecks](#cdk-nag-awssolutionschecks), [HIPAASecurityChecks](#cdk-nag-hipaasecuritychecks), [NIST80053R4Checks](#cdk-nag-nist80053r4checks), [NIST80053R5Checks](#cdk-nag-nist80053r5checks), [PCIDSS321Checks](#cdk-nag-pcidss321checks) +__Implemented by__: [AwsSolutionsChecks](#cdk-nag-awssolutionschecks), [HIPAASecurityChecks](#cdk-nag-hipaasecuritychecks), [NIST80053R4Checks](#cdk-nag-nist80053r4checks), [NIST80053R5Checks](#cdk-nag-nist80053r5checks), [NZISM36Checks](#cdk-nag-nzism36checks), [PCIDSS321Checks](#cdk-nag-pcidss321checks) ### Initializer diff --git a/README.md b/README.md index f3f3bef74c..b2d69d8544 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ See [RULES](./RULES.md) for more information on all the available packs. 3. [NIST 800-53 rev 4](./RULES.md#nist-800-53-rev-4) 4. [NIST 800-53 rev 5](./RULES.md#nist-800-53-rev-5) 5. [PCI DSS 3.2.1](./RULES.md#pci-dss-321) +6. [NZISM 3.6](./RULES.md#nzism-3.6) [RULES](./RULES.md) also includes a collection of [additional rules](./RULES.md#additional-rules) that are not currently included in any of the pre-built NagPacks, but are still available for inclusion in custom NagPacks. diff --git a/RULES.md b/RULES.md index 58f8b681fb..6800ecb609 100644 --- a/RULES.md +++ b/RULES.md @@ -695,6 +695,118 @@ Unimplemented rules from the AWS PCI DSS 3.2.1 Conformance Pack. | [ssm-document-not-public](https://docs.aws.amazon.com/config/latest/developerguide/ssm-document-not-public.html) | SSM documents are not public. | 1.2, 1.2.1, 1.3, 1.3.1, 1.3.2, 1.3.4, 1.3.6, 2.2.2 | | [vpc-sg-open-only-to-authorized-ports](https://docs.aws.amazon.com/config/latest/developerguide/vpc-sg-open-only-to-authorized-ports.html) | The VPC Security Group restricts IPv4 TCP traffic on unauthorized ports.[2](#vpc-sg-open-only-to-authorized-ports) | 1.2, 1.2.1, 1.3, 1.3.1, 1.3.2, 2.2.2 | +## NZISM 3.6 + +The [Operational Best Practices for NZISM 3.6](https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-nzism.html) Conformance pack offers a collection of AWS Config Rules that enable customers to align to a subset of the Zealand Government Communications Security Bureau (GCSB) Information Security Manual (NZISM) standards. NZISM 3.6 NagPack implements many of the checks within the conformance pack. + +Some tests in this pack map to multiple NZISM controls. For tests which have at least one control that has a 'MUST' requirement, the test will return an error if not compliant. For tests which only have 'SHOULD' requirments, the pack will raise warnings if not compliant. + +### Errors + +| Rule ID | Cause | Explanation | Relevent Control ID(s) | +| ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| NZISM3.6-APIGWExecutionLoggingEnabled | The API Gateway stage does not have execution logging enabled for all methods. | API Gateway logging displays detailed views of users who accessed the API and the way they accessed the API. This insight enables visibility of user activities. | Control IDs: SHOULD(16.6.10.C.02[CID:2013]), MUST(23.5.11.C.01[CID:7496]) | +| NZISM3.6-CloudFrontDistributionAccessLogging | The CloudFront distribution does not have access logging enabled. | Enabling access logs helps operators track all viewer requests for the content delivered through the Content Delivery Network | Control IDs: SHOULD(16.6.10.C.02[CID:2013]), MUST(23.5.11.C.01[CID:7496]) | +| NZISM3.6-CloudFrontDistributionWAFIntegration | The CloudFront distribution requires integration with WAF. | 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 | Control IDs: MUST(19.1.12.C.01[CID:3562]) | +| NZISM3.6-CloudFrontDistributionHttpsViewerNoOutdatedSSL | The CloudFront distribution allows for SSLv3 or TLSv1 for HTTPS viewer connections. | 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 | Control IDs: MUST(16.1.37.C.01[CID:1847]) | +| NZISM3.6-CloudTrailCloudWatchLogsEnabled | The trail does not have CloudWatch logs enabled. | Use Amazon CloudWatch to centrally collect and manage log event activity. Inclusion of AWS CloudTrail data provides details of API call activity within your AWS account | Control IDs: SHOULD(16.6.6.C.02[CID:1998]), MUST(16.4.35.C.02[CID:6860]) | +| NZISM3.6-CloudTrailLogFileValidationEnabled | The trail does not have validation enabled. | Utilize AWS CloudTrail log file validation to check the integrity of CloudTrail logs. Log file validation helps determine if a log file was modified or deleted or unchanged after CloudTrail delivered it. This feature is built using industry standard algorithms: SHA-256 for hashing and SHA-256 with RSA for digital signing. This makes it computationally infeasible to modify, delete or forge CloudTrail log files without detection | Control IDs: MUST(16.6.12.C.01[CID:2022], 23.5.11.C.01[CID:7496]) | +| NZISM3.6-CloudWatchLogGroupRetentionPeriod | The CloudWatch Log Group does not have an explicit retention period configured. | Ensure a minimum duration of event log data is retained for your log groups to help with troubleshooting and forensics investigations. The lack of available past event log data makes it difficult to reconstruct and identify potentially malicious events | Control IDs: SHOULD(16.6.6.C.02[CID:1998]), MUST(16.6.13.C.01[CID:2028]) | +| NZISM3.6-CloudWatchLogGroupEncrypted | The CloudWatch Log Group is not encrypted with an AWS KMS key. | To help protect sensitive data at rest, ensure encryption is enabled for your Amazon CloudWatch Log Groups | Control IDs: MUST(16.6.12.C.01[CID:2022], 23.5.11.C.01[CID:7496]) | +| NZISM3.6-DMSReplicationNotPublic | The DMS replication instance is public. | DMS replication instances can contain sensitive information and access control is required for such accounts | Control IDs: MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]) | +| NZISM3.6-DynamoDBAutoScalingEnabled | The provisioned capacity DynamoDB table does not have Auto Scaling enabled on its indexes. | Amazon DynamoDB auto scaling uses the AWS Application Auto Scaling service to adjust provisioned throughput capacity that automatically responds to actual traffic patterns. This enables a table or a global secondary index to increase its provisioned read/write capacity to handle sudden increases in traffic, without throttling | Control IDs: MUST(22.1.23.C.01[CID:4829] | +| NZISM3.6-DynamoDBInBackupPlan | The DynamoDB table is not in an AWS Backup plan. | To help with data back-up processes, ensure your Amazon DynamoDB tables are a part of an AWS Backup plan. AWS Backup is a fully managed backup service with a policy-based backup solution. This solution simplifies your backup management and enables you to meet your business and regulatory backup compliance requirements | Control IDs: MUST(22.1.26.C.01[CID:4849]) | +| NZISM3.6-DynamoDBPITREnabled | DynamoDB table does not have Point-in-time Recovery enabled. | The recovery maintains continuous backups of your table for the last 35 days | Control IDs: MUST(22.1.26.C.01[CID:4849]) | +| NZISM3.6-EC2EBSInBackupPlan | The EC2 instance is associated with a public IP address. | Manage access to the AWS Cloud by ensuring Amazon Elastic Compute Cloud (Amazon EC2) instances cannot be publicly accessed. Amazon EC2 instances can contain sensitive information and access control is required for such accounts | Control IDs: MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]) | +| NZISM3.6-EC2InstancesInVPC | 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 | Control IDs: MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]) | +| NZISM3.6-EC2IMDSv2 | THe Ec2 Instance does not use IMDSv2. | IMDSv2 adds session-based controls to http requests to restrict access to the Instance Meta Data Service | Control IDs: MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]) | +| NZISM3.6-EFSInBackupPlan | The EFS is not in an AWS Backup plan. | To help with data back-up processes, ensure your Amazon Elastic File System (Amazon EFS) file systems are a part of an AWS Backup plan. AWS Backup is a fully managed backup service with a policy-based backup solution. This solution simplifies your backup management and enables you to meet your business and regulatory backup compliance requirements | Control IDs: MUST(22.1.26.C.01[CID:4849]) | +| NZISM3.6-EFSEncrypted | 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) | Control IDs: SHOULD(17.1.46.C.04[CID:2082], 22.1.24.C.04[CID:4839]) | +| NZISM3.6-ElastiCacheRedisClusterAutomaticBackup | The ElastiCache Redis cluster does not retain automatic backups for at least 15 day. | 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 | Control IDs: MUST(22.1.26.C.01[CID:4849]) | +| NZISM3.6-ALBHttpToHttpsRedirection | The ALBs HTTP listeners are not configured to redirect to HTTPS. | 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 | Control IDs: MUST(16.1.37.C.01[CID:1847], 17.1.48.C.03[CID:2091]) | +| NZISM3.6-ALBWAFEnabled | The ALB is not associated with AWS WAFv2 web ACL. | A WAF helps to protect your web applications or APIs against common web exploits. These web exploits may affect availability, compromise security, or consume excessive resources within your environment | Control IDs: SHOULD(20.3.7.C.02[CID:4333]), MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]) | +| NZISM3.6-ELBCrossZoneLoadBalancingEnabled | Load Balancers are not cross zone enabled. | Enable cross-zone load balancing for your Classic Load Balancers (CLBs) to help maintain adequate capacity and availability. The cross-zone load balancing reduces the need to maintain equivalent numbers of instances in each enabled availability zone. It also improves your application's ability to handle the loss of one or more instances | Control IDs: MUST(22.1.23.C.01[CID:4829])] | +| NZISM3.6-ELBLoggingEnabled | The ELB does not have logging enabled. | 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 | Control IDs: SHOULD(16.6.10.C.02[CID:2013]), MUST(23.5.11.C.01[CID:7496]) | +| NZISM3.6-ELBTlsHttpsListenersOnly | The Classic Load Balancer does not restrict its listeners to only the SSL and HTTPS protocol. | Ensure that your Classic Load Balancers (CLBs) are configured with SSL or HTTPS listeners. Because sensitive data can exist, enable encryption in transit to help protect that data | 14.5.8.C.01(Control IDs: SHOULD(14.5.8.C.01[CID:1667], 22.1.24.C.04[CID:4839])), MUST(16.1.37.C.01[CID:1847], 17.1.48.C.03[CID:2091]) | +| NZISM3.6-lambda-function-public-access-prohibited | Lambda function policies should not be publically invokable. | | Control IDs: MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]) | +| NZISM3.6-OpenSearchInVPCOnly | The OpenSearch Service domain is not running within a VPC. | VPCs help secure your AWS resources and provide an extra layer of protection | Control IDs: SHOULD(19.1.14.C.02[CID:3623]), MUST(19.1.12.C.01[CID:3562]) | +| NZISM3.6-OpenSearchNodeToNodeEncryption | The OpenSearch Service domain does not have node-to-node encryption enabled. | Because sensitive data can exist, enable encryption in transit to help protect that data within your Amazon OpenSearch Service (OpenSearch Service) domains | Control IDs: SHOULD(22.1.24.C.04[CID:4839]), MUST(16.1.37.C.01[CID:1847]) | +| NZISM3.6-RDSInstanceDeletionProtectionEnabled | The RDS DB Instance or Aurora Cluster does not have deletion protection enabled. | Ensure Amazon Relational Database Service (Amazon RDS) instances and clusters have deletion protection enabled. Use deletion protection to prevent your Amazon RDS DB instances and clusters from being accidentally or maliciously deleted, which can lead to loss of availability for your application | Control IDs: MUST(22.1.26.C.01[CID:4849]) | +| NZISM3.6-RDSMultiAZSupport | The RDS DB Instance does not have multi-AZ support. | Ensure Amazon Relational Database Service (Amazon RDS) instances and clusters have deletion protection enabled. Use deletion protection to prevent your Amazon RDS DB instances and clusters from being accidentally or maliciously deleted, which can lead to loss of availability for your applications | Control IDs: MUST(22.1.23.C.01[CID:4829]) | +| NZISM3.6-RDSInBackupPlan | The RDS DB instance is not in an AWS Backup plan. | To help with data back-up processes, ensure your Amazon Relational Database Service (Amazon RDS) instances are a part of an AWS Backup plan. AWS Backup is a fully managed backup service with a policy-based backup solution. This solution simplifies your backup management and enables you to meet your business and regulatory backup compliance requirements | Control IDs: MUST(22.1.26.C.01[CID:4849]) | +| NZISM3.6-RDSInstancePublicAccess | The RDS DB Instance allows public access. | Amazon RDS database instances can contain sensitive information, and principles and access control is required for such accounts | Control IDs: SHOULD(19.1.14.C.02[CID:3623]), MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]) | +| NZISM3.6-RedshiftBackupEnabled | The Redshift cluster does not have automated snapshots enabled or the retention period is not between 1 and 35 days. | To help with data back-up processes, ensure your Amazon Redshift clusters have automated snapshots. When automated snapshots are enabled for a cluster, Redshift periodically takes snapshots of that cluster. By default, Redshift takes a snapshot every eight hours or every 5 GB per node of data changes, or whichever comes first | Control IDs: MUST(22.1.26.C.01[CID:4849]) | +| NZISM3.6-RedshiftClusterMaintenanceSettings | The Redshift cluster does not have version upgrades enabled, automated snapshot retention periods enabled, and an explicit maintenance window configured. | Ensure that Amazon Redshift clusters have the preferred settings for your organization. Specifically, that they have preferred maintenance windows and automated snapshot retention periods for the database | SHOULD(12.4.4.C.06[CID:3453]), MUST(12.4.4.C.02[CID:3449]) | +| NZISM3.6-RedshiftClusterPublicAccess | Redshift must not be made publically avaialble. | Amazon Redshift clusters can contain sensitive information and principles and access control is required for such accounts | Control IDs: SHOULD(19.1.14.C.02[CID:3623]), MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]) | +| NZISM3.6-RedshiftRequireTlsSSL | The Redshift cluster must use TLS/SSL encryption. | Ensure that your Amazon Redshift clusters require TLS/SSL encryption to connect to SQL clients. Because sensitive data can exist, enable encryption in transit to help protect that data | Control IDs: SHOULD(22.1.24.C.04[CID:4839]), MUST(17.1.48.C.03[CID:2091]) | +| NZISM3.6-S3BucketLoggingEnabled | The S3 Buckets does not have server access logs enable. | Amazon Simple Storage Service (Amazon S3) server access logging provides a method to monitor the network for potential cybersecurity events. The events are monitored by capturing detailed records for the requests that are made to an Amazon S3 bucket. Each access log record provides details about a single access request. The details include the requester, bucket name, request time, request action, response status, and an error code, if relevant | Control IDs: MUST(22.1.26.C.01[CID:4849]) | +| NZISM3.6-S3BucketVersioningEnabled | The S3 Bucket does not have versioning enable. | Use versioning to preserve, retrieve, and restore every version of every object stored in your Amazon S3 bucket. Versioning helps you to easily recover from unintended user actions and application failures | Control IDs: MUST(22.1.26.C.01[CID:4849]) | +| NZISM3.6-SageMakerNotebookNoDirectInternetAccess | The SageMaker notebook does not disable direct internet access. | By preventing direct internet access, you can keep sensitive data from being accessed by unauthorized users | Control IDs: MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]) | +| NZISM3.6-VPCDefaultSecurityGroupClosed | The VPC does not have an associated Flow Log. | The VPC flow logs provide detailed records for information about the IP traffic going to and from network interfaces in your Amazon | Control IDs: MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]) | +| NZSISM3.6-VPCFlowLogs | VPC does not have an Assocated Flow Log. | Enable a Flow Log for the VPC | Control IDs: MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]) | +| NZISM3.6-RDSLoggingEnabled | The non-Aurora RDS DB instance or Aurora cluster does not have all CloudWatch log types exported. | | Control IDs: SHOULD(16.6.10.C.02[CID:2013], 20.4.4.C.02[CID:4441], 20.4.5.C.02[CID:4445]), MUST(23.5.11.C.01[CID:7496]) | +| NZISM3.6-WAFv2LoggingEnabled | The WAFv2 web ACL does not have logging enabled. | AWS WAF logging provides detailed information about the traffic that is analyzed by your web ACL. The logs record the time that AWS WAF received the request from your AWS resource, information about the request, and an action for the rule that each request matched. | Control IDs: SHOULD(16.6.10.C.02[CID:2013]), MUST(23.5.11.C.01[CID:7496]) | + +### Warnings. + +| Rule ID | Cause | Explanation | Relevent Control ID(s) | +| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- | +| NZISM3.6-CloudFrontDistributionAccessLogging | The CloudFront distribution does not have access logging enabled. | Enabling access logs helps operators track all viewer requests for the content delivered through the Content Delivery Network. | Control IDs: SHOULD(16.6.10.C.02[CID:2013]), MUST(23.5.11.C.01[CID:7496]) | +| NZISM3.6-CloudTrailEncryptionEnabled | The trail does not have encryption enabled. | Because sensitive data may exist and to help protect data at rest, ensure encryption is enabled for your AWS CloudTrail trails | Control IDs: SHOULD(17.1.46.C.04[CID:2082]) | +| NZISM3.6-CloudfrontDefaultRootObjectConfigured | The Cloudfront distribution requires a default object. | Specifying a default root object lets you avoid exposing the contents of your distribution | Control IDs: SHOULD(14.5.6.C.01[CID:1661]) | +| NZISM3.6-EC2EBSVolumeEncrypted | The EBS volume has encryption disabled. | With EBS encryption, you aren not 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. | Control IDs: SHOULD(17.1.46.C.04[CID:2082], 22.1.24.C.04[CID:4839])) | +| NZISM3.6-EC2RestrictedSSH | The Security Group allows unrestricted SSH access. | Not allowing ingress (or remote) traffic from 0.0.0.0/0 or ::/0 to port 22 on your resources helps to restrict remote access | Control IDs: SHOULD(17.5.8.C.02[CID:2726]) | +| NZISM3.6-ECSTaskDefinitionUserForHostMode | 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 | Control IDs: SHOULD(14.1.8.C.01[CID:1149]) | +| NZISM3.6-ElasticBeanstalkManagedUpdatesEnabled | The Elastic Beanstalk environment does not have enhanced health reporting enabled. | Enabling managed platform updates for an Amazon Elastic Beanstalk environment ensures that the latest available platform fixes, updates, and features for the environment are installed. Keeping up to date with patch installation is a best practice in securing systems | Control IDs: SHOULD(12.4.4.C.05[CID:3452]) | +| NZISM3.6-IAMPolicyNoStatementsWithAdminAccess | The IAM policy grants admin access, meaning the policy allows a principal to perform all actions on all resources. | AWS Identity and Access Management (IAM) can help you incorporate the principles of least privilege and separation of duties with access permissions and authorizations, by ensuring that IAM groups have at least one IAM user. Placing IAM users in groups based on their associated permissions or job function is one way to incorporate least privilege | Control IDs: SHOULD(16.3.5.C.02[CID:1946]) | +| NZISM3.6-KMSBackingKeyRotationEnabled | The KMS Symmetric key does not have automatic key rotation enabled. | Enable key rotation to ensure that keys are rotated once they have reached the end of their crypto period | Control IDs: SHOULD(17.9.25.C.01[CID:3021]) | +| NZISM3.6-OpenSearchEncryptedAtRest | The OpenSearch Service domain 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 OpenSearch Service (OpenSearch Service) domains | (Control IDs: SHOULD(17.1.46.C.04[CID:2082], 20.4.4.C.02[CID:4441], 22.1.24.C.04[CID:4839])) | +| NZISM3.6-RDSAutomaticMinorVersionUpgradeEnabled | RDS DB Instance is not configured for minor patches. | Provides automatic Patching in the Database | Control IDs: SHOULD(12.4.4.C.05[CID:3452]) | +| NZISM3.6-RDSStorageEncrypted | The RDS DB Instance or Aurora Cluster does not have storage encrypted. | Because sensitive data can exist at rest in Amazon RDS instances, enable encryption at rest to help protect that data | Control IDs: SHOULD(17.1.46.C.04[CID:2082], 20.4.4.C.02[CID:4441], 22.1.24.C.04[CID:4839]) | +| NZISM3.6-RedshiftClusterConfiguration | The Redshift cluster does not have encryption or audit logging enabled. | To protect data at rest, ensure that encryption is enabled for your Amazon Redshift clusters. You must also ensure that required configurations are deployed on Amazon Redshift clusters. The audit logging should be enabled to provide information about connections and user activities in the database | Control IDs: SHOULD(17.1.46.C.04[CID:2082], 20.4.4.C.02[CID:4441], 22.1.24.C.04[CID:4839]) | +| NZISM3.6-S3BucketSSLRequestsOnly | The S3 Bucket or bucket policy does not require requests to use SSL. | To help protect data in transit, ensure that your Amazon Simple Storage Service (Amazon S3) buckets require requests to use Secure Socket Layer (SSL). Because sensitive data can exist, enable encryption in transit to help protect that data. | Control IDs: SHOULD(22.1.24.C.04[CID:4839]) | +| NZISM3.6-S3BucketPublicReadProhibited | The S3 Bucket does not prohibit public read access through its Block Public Access configurations and bucket ACLs. | The management of access should be consistent with the classification of the data | Control IDs: SHOULD(22.1.24.C.03[CID:4838]) | +| NZISM3.6-S3BucketPublicWriteProhibited | The S3 Bucket does not prohibit public write access through its Block Public Access configurations and bucket ACLs. | The management of access should be consistent with the classification of the data | Control IDs: SHOULD(22.1.24.C.03[CID:4838]) | +| NZISM3.6-S3DefaultEncryptionKMS | The S3 Bucket is not encrypted with a KMS Key by default. | Ensure that encryption is enabled for your Amazon Simple Storage Service (Amazon S3) buckets. Because sensitive data can exist at rest in an Amazon S3 bucket, enable encryption at rest to help protect that data | (Control IDs: SHOULD(17.1.46.C.04[CID:2082])) | +| NZISM3.6-SageMakerEndpointConfigurationKMSKeyConfigured | The SageMaker resource endpoint is not encrypted with a KMS key. | Because sensitive data can exist at rest in SageMaker endpoint, enable encryption at rest to help protect that data | Control IDs: SHOULD(22.1.24.C.04[CID:4839]) | +| NZISM3.6-SageMakerNotebookInstanceKMSKeyConfigured | The SageMaker notebook is not encrypted with a KMS key. | Because sensitive data can exist at rest in SageMaker notebook, enable encryption at rest to help protect that data | Control IDs: SHOULD(22.1.24.C.04[CID:4839]) | +| NZISM3.6-SecretsManagerUsingKMSKey | The secret is not encrypted with a KMS Customer managed key. | To help protect data at rest, ensure encryption with AWS Key Management Service (AWS KMS) is enabled for AWS Secrets Manager secrets. Because sensitive data can exist at rest in Secrets Manager secrets, enable encryption at rest to help protect that data | Control IDs: SHOULD(22.1.24.C.04[CID:4839]) | +| NZISM3.6-SNSEncryptedKMS | The SNS topic does not have KMS encryption enabled. | To help protect data at rest, ensure that your Amazon Simple Notification Service (Amazon SNS) topics require encryption using AWS Key Management Service (AWS KMS) Because sensitive data can exist at rest in published messages, enable encryption at rest to help protect that data | Control IDs: SHOULD(22.1.24.C.04[CID:4839]) | +| NZISM3.6-EC2SecurityGroupOnlyTcp443 | Only port tcp 443 shoudl be permitted in ingress security group. | Not allowing ingress (or remote) traffic to ports other than tcp port 443 helps improve security | Control IDs: SHOULD(18.1.13.C.02[CID:3205]) | + +### Excluded Rules + +Unimplemented rules from the NSISM 3.6 Conformance Pack. + +| AWS Config Rule Name | Summary | Relevant Control ID(s) | Reason for Exclusion from NagPak.. | +| ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | +| NZISM3.6-acm-certificate-expiration-check | AWS Certificate Manager Certificates in your account are valid and not marked for expiration within the specified number of days. | SHOULD 14.5.8.C.01[CID:1667] | Account Level Check | +| NZISM3.6-cloudtrail-enabled | The AWS account has cloudtrail enabled. | 16.6.6.C.02[CID:1998], 16.6.10.C.02[CID:2013], 16.4.35.C.02[CID:6860], 23.5.11.C.01[CID:7496] | Account Level Check | +| NZISM3.6-cloudtrail-s3-dataevents-enabled | The AWS Account has at least once AWS CloudTrail that logs Amazon S3 data events for all S3 buckets. | SHOULD 22.1.24.C.03[CID:4838] | Account Level Check | +| NZISM3.6-cloudtrail-security-trail-enabled | The AWS Account has at least once AWS CloudTrail that records global service events, is a multi-region trail, has Log file validation enabled, encrypted with a KMS key, records events for reads and writes, records management events, and does not exclude any management events. | MUST 16.4.35.C.03[CID:6861] | Account Level Check | +| NZISM3.6-ebs-snapshot-public-restorable-check | EBS snapshots can be publicly restored . | SHOULD 22.1.24.C.03[CID:4838] | Account Level Check | +| NZISM3.6-ec2-critical-security-patch-auto-approval | Patch Baselines for Windows and/or Linux have been configured in Patch Manager, including auto-approval of critical security patches within 2 days of release | SHOULD 12.4.4.C.04[CID:3451] | Account Level Check | +| NZISM3.6-ec2-ebs-encryption-by-default | Default encryption for EBS volumes is enabled at the AWS Account level. | SHOULD 17.1.46.C.04[CID:2082] | Account Level Check | +| NZISM3.6-ec2-hardening-and-state-management | Hardened EC2 server image build processes and State Manager Associations are configured to remove unneeded components and services, and install anti-malware software and log agents | SHOULD 14.1.8.C.01[CID:1149] | Account Level Check | +| NZISM3.6-ec2-instance-managed-by-systems-manager | EC2 instances are managed by Systems Manager. | SHOULD 14.1.8.C.01[CID:1149] | Account Level Check | +| NZISM3.6-ec2-managedinstance-association-compliance-status-check | Managed EC2 instances are compliant with their association's standards. | SHOULD 14.1.8.C.01[CID:1149] | Account Level Check | +| NZISM3.6-ec2-managedinstance-patch-compliance-status-check | EC2 instances are compliant with their patch requirements. | MUST 12.4.4.C.02[CID:3449], SHOULD 12.4.4.C.04[CID:3451], SHOULD 12.4.4.C.05[CID:3452], SHOULD 12.4.4.C.06[CID:3453] | Account Level Check | +| NZISM3.6-ecr-private-image-scanning-enabled | | MUST 12.4.4.C.02[CID:3449] | Account Level Check | +| NZISM3.6-ecs-containers-readonly-access | | SHOULD 14.1.8.C.01[CID:1149] | Account Level Check | +| NZISM3.6-emr-master-no-public-ip | EMR clusters' master nodes have no public IP. | MUST 19.1.12.C.01[CID:3562], MUST 23.4.10.C.01[CID:7466] | Account Level Check | +| NZISM3.6-federate-with-central-idp | | MUST 19.1.12.C.01[CID:3562], MUST 18.4.9.C.01[CID:3815], SHOULD 18.4.12.C.01[CID:3875], MUST 23.4.10.C.01[CID:7466] | Account Level Check | +| NZISM3.6-iam-password-policy | Account password policy for IAM users meet the specified requirements indicated in the parameters. | SHOULD 16.1.40.C.02[CID:1858] | Account Level Check | +| NZISM3.6-iam-root-access-key-check | The Account IAM Root User has an access key(s) . | SHOULD 16.3.5.C.02[CID:1946] | Account Level Check | +| NZISM3.6-iam-user-unused-credentials-check | IAM User passwords and active access keys have been used within a specified number of days. | SHOULD 16.1.46.C.02[CID:1893], MUST 16.4.33.C.01[CID:6852] | Account Level Check | +| NZISM3.6-kms-cmk-for-each-data-classification | | SHOULD 17.9.25.C.01[CID:3021] | Account Level Check | +| NZISM3.6-mfa-enabled-for-iam-console-access | IAM Users have MFA enabled for console access. | SHOULD 16.1.35.C.02[CID:1841], SHOULD 16.4.31.C.02[CID:6843], SHOULD 16.7.34.C.02[CID:6953], MUST 23.3.19.C.01[CID:7436], MUST 23.3.19.C.01[CID:7437] | Account Level Check | +| NZISM3.6-rds-snapshot-encrypted | RDS snapshots are encrypted. | SHOULD 17.1.46.C.04[CID:2082], SHOULD 20.4.4.C.02[CID:4441], SHOULD 22.1.24.C.04[CID:4839] | Account Level Check | +| NZISM3.6-rds-snapshots-public-prohibited | RDS snapshots are not public. | SHOULD 20.4.4.C.02[CID:4441] | Account Level Check | +| NZISM3.6-root-account-hardware-mfa-enabled | The AWS Account root user is hardware MFA enabled. | SHOULD 16.1.35.C.02[CID:1841], SHOULD 16.4.31.C.02[CID:6843], SHOULD 16.7.34.C.02[CID:6953], MUST 23.3.19.C.01[CID:7436], MUST 23.3.19.C.01[CID:7437] | Account Level Check | +| NZISM3.6-root-account-mfa-enabled | The AWS Account root user is MFA enabled. | SHOULD 16.1.35.C.02[CID:1841], MUST 23.3.19.C.01[CID:7436], MUST 23.3.19.C.01[CID:7437] | Account Level Check | +| NZISM3.6-securityhub-enabled | The AWS Account has Security Hub enabled. | SHOULD 18.4.12.C.01[CID:3875] | Account Level Check | +| NZISM3.6-ssm-document-not-public | SSM documents are not public. | MUST 23.4.10.C.01[CID:7466] | Account Level Check | + ## Additional Rules A collection of community rules that are not currently included in any of the pre-built NagPacks, but are still available for inclusion in [custom NagPacks](https://github.com/cdklabs/cdk-nag/blob/main/docs/NagPack.md). diff --git a/src/index.ts b/src/index.ts index 576f321031..93a59b5ddb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,4 +13,5 @@ export * from './packs/hipaa-security'; export * from './packs/nist-800-53-r4'; export * from './packs/nist-800-53-r5'; export * from './packs/pci-dss-321'; +export * from './packs/nzism-v36-1022-20'; export * as rules from './rules'; diff --git a/src/packs/nzism-v36-1022-20.ts b/src/packs/nzism-v36-1022-20.ts new file mode 100644 index 0000000000..ab74dd2db4 --- /dev/null +++ b/src/packs/nzism-v36-1022-20.ts @@ -0,0 +1,870 @@ +/* +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ +import { CfnResource } from 'aws-cdk-lib'; +import { IConstruct } from 'constructs'; +import { NagPack, NagPackProps } from '../nag-pack'; +import { NagMessageLevel } from '../nag-rules'; +import { APIGWExecutionLoggingEnabled } from '../rules/apigw'; +import { + CloudFrontDistributionAccessLogging, + CloudFrontDistributionHttpsViewerNoOutdatedSSL, + CloudFrontDistributionWAFIntegration, + CloudFrontDefaultRootObjectConfigured, +} from '../rules/cloudfront'; +import { + CloudTrailCloudWatchLogsEnabled, + CloudTrailEncryptionEnabled, + CloudTrailLogFileValidationEnabled, +} from '../rules/cloudtrail'; +import { + CloudWatchLogGroupEncrypted, + CloudWatchLogGroupRetentionPeriod, +} from '../rules/cloudwatch'; +import { DMSReplicationNotPublic } from '../rules/dms'; +import { + DynamoDBAutoScalingEnabled, + DynamoDBInBackupPlan, + DynamoDBPITREnabled, +} from '../rules/dynamodb'; +import { + EC2EBSInBackupPlan, + EC2InstanceNoPublicIp, + EC2InstancesInVPC, + EC2RestrictedSSH, + EC2EBSVolumeEncrypted, + EC2SecurityGroupOnlyTcp443, + EC2IMDSv2Enabled, +} from '../rules/ec2'; +import { ECSTaskDefinitionUserForHostMode } from '../rules/ecs'; +import { EFSEncrypted, EFSInBackupPlan } from '../rules/efs'; +import { ElastiCacheRedisClusterAutomaticBackup } from '../rules/elasticache'; +import { ElasticBeanstalkManagedUpdatesEnabled } from '../rules/elasticbeanstalk'; +import { + ALBHttpToHttpsRedirection, + ALBWAFEnabled, + ELBCrossZoneLoadBalancingEnabled, + ELBLoggingEnabled, + ELBTlsHttpsListenersOnly, +} from '../rules/elb'; +import { IAMPolicyNoStatementsWithAdminAccess } from '../rules/iam'; +import { KMSBackingKeyRotationEnabled } from '../rules/kms'; +import { LambdaFunctionPublicAccessProhibited } from '../rules/lambda'; +import { + OpenSearchEncryptedAtRest, + OpenSearchInVPCOnly, + OpenSearchNodeToNodeEncryption, +} from '../rules/opensearch'; +import { + RDSAutomaticMinorVersionUpgradeEnabled, + RDSInBackupPlan, + RDSInstanceDeletionProtectionEnabled, + RDSInstancePublicAccess, + RDSLoggingEnabled, + RDSMultiAZSupport, + RDSStorageEncrypted, +} from '../rules/rds'; +import { + RedshiftRequireTlsSSL, + RedshiftBackupEnabled, + RedshiftClusterConfiguration, + RedshiftClusterMaintenanceSettings, + RedshiftClusterPublicAccess, +} from '../rules/redshift'; +import { + S3BucketLevelPublicAccessProhibited, + S3BucketLoggingEnabled, + S3BucketPublicReadProhibited, + S3BucketPublicWriteProhibited, + S3BucketSSLRequestsOnly, + S3BucketVersioningEnabled, + S3DefaultEncryptionKMS, +} from '../rules/s3'; +import { + SageMakerEndpointConfigurationKMSKeyConfigured, + SageMakerNotebookInstanceKMSKeyConfigured, + SageMakerNotebookNoDirectInternetAccess, +} from '../rules/sagemaker'; +import { SecretsManagerUsingKMSKey } from '../rules/secretsmanager'; +import { SNSEncryptedKMS } from '../rules/sns'; +import { + VPCFlowLogsEnabled, + VPCDefaultSecurityGroupClosed, +} from '../rules/vpc'; +import { WAFv2LoggingEnabled } from '../rules/waf'; + +/** + * Check for NZISM v36-1022-20 compliance. + * Based on the NZISM v36-1022-20: + * */ + +export class NZISM36Checks extends NagPack { + constructor(props?: NagPackProps) { + super(props); + this.packName = 'NZISM3.6'; + } + public visit(node: IConstruct): void { + if (node instanceof CfnResource) { + this.checkELB(node); + this.checkAPIGW(node); + this.checkCloudTrail(node); + this.checkCloudFront(node); + this.checkKMS(node); + this.checkCloudWatch(node); + this.checkRDS(node); + this.checkECS(node); + this.checkEFS(node); + this.checkDMS(node); + this.checkDynamoDB(node); + this.checkEC2(node); + this.checkElasticBeanstalk(node); + this.checkElastiCache(node); + this.checkLambda(node); + this.checkOpenSearch(node); + this.checkIAM(node); + this.checkRedshift(node); + this.checkS3(node); + this.checkSageMaker(node); + this.checkSecretsManager(node); + this.checkSNS(node); + this.checkVPC(node); + this.checkWAF(node); + } + } + + /** + * Check API Gateway Resources + * E + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkAPIGW(node: CfnResource): void { + this.applyRule({ + info: 'The API Gateway stage does not have execution logging enabled for all methods - (Control IDs: SHOULD(16.6.10.C.02[CID:2013]), MUST(23.5.11.C.01[CID:7496]))', + explanation: + 'API Gateway logging displays detailed views of users who accessed the API and the way they accessed the API. This insight enables visibility of user activities.', + level: NagMessageLevel.ERROR, + rule: APIGWExecutionLoggingEnabled, + node: node, + }); + } + + /** + * Check CloudFront Resources + * @param node + * @param ignores + */ + private checkCloudFront(node: CfnResource): void { + this.applyRule({ + info: 'The CloudFront distribution does not have access logging enabled. - (Control IDs: SHOULD(16.6.10.C.02[CID:2013]), MUST(23.5.11.C.01[CID:7496]))', + explanation: + 'Enabling access logs helps operators track all viewer requests for the content delivered through the Content Delivery Network.', + level: NagMessageLevel.ERROR, + rule: CloudFrontDistributionAccessLogging, + node: node, + }); + this.applyRule({ + info: 'The CloudFront distribution requires integration with WAF - (Control IDs: MUST(19.1.12.C.01[CID:3562]))', + 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: NagMessageLevel.ERROR, + rule: CloudFrontDistributionWAFIntegration, + node: node, + }); + + this.applyRule({ + info: 'The CloudFront distribution allows for SSLv3 or TLSv1 for HTTPS viewer connections - (Control IDs: MUST(16.1.37.C.01[CID:1847]))', + 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: NagMessageLevel.ERROR, + rule: CloudFrontDistributionHttpsViewerNoOutdatedSSL, + node: node, + }); + + this.applyRule({ + info: 'The Cloudfront distribution requires a default object - (Control IDs: SHOULD(14.5.6.C.01[CID:1661]))', + explanation: + 'Specifying a default root object lets you avoid exposing the contents of your distribution', + level: NagMessageLevel.WARN, + rule: CloudFrontDefaultRootObjectConfigured, + node: node, + }); + } + + /** + * Check CloudTrail Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkCloudTrail(node: CfnResource): void { + this.applyRule({ + info: 'The trail does not have CloudWatch logs enabled - (Control IDs: SHOULD(16.6.6.C.02[CID:1998]), MUST(16.4.35.C.02[CID:6860]))', + explanation: + 'Use Amazon CloudWatch to centrally collect and manage log event activity. Inclusion of AWS CloudTrail data provides details of API call activity within your AWS account.', + level: NagMessageLevel.ERROR, + rule: CloudTrailCloudWatchLogsEnabled, + node: node, + }); + + this.applyRule({ + info: 'The trail does not have encryption enabled - (Control IDs: SHOULD(17.1.46.C.04[CID:2082]))', + explanation: + 'Because sensitive data may exist and to help protect data at rest, ensure encryption is enabled for your AWS CloudTrail trails.', + level: NagMessageLevel.WARN, + rule: CloudTrailEncryptionEnabled, + node: node, + }); + + this.applyRule({ + info: 'The trail does not have log file validation - (Control IDs: MUST(16.6.12.C.01[CID:2022], 23.5.11.C.01[CID:7496]))', + explanation: + 'Utilize AWS CloudTrail log file validation to check the integrity of CloudTrail logs. Log file validation helps determine if a log file was modified or deleted or unchanged after CloudTrail delivered it. This feature is built using industry standard algorithms: SHA-256 for hashing and SHA-256 with RSA for digital signing. This makes it computationally infeasible to modify, delete or forge CloudTrail log files without detection.', + level: NagMessageLevel.ERROR, + rule: CloudTrailLogFileValidationEnabled, + node: node, + }); + } + + /** + * Check CloudWatch Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + + private checkCloudWatch(node: CfnResource): void { + this.applyRule({ + info: 'The CloudWatch Log Group does not have an explicit retention period configured - (Control IDs: SHOULD(16.6.6.C.02[CID:1998]), MUST(16.6.13.C.01[CID:2028]))', + explanation: + 'Ensure a minimum duration of event log data is retained for your log groups to help with troubleshooting and forensics investigations. The lack of available past event log data makes it difficult to reconstruct and identify potentially malicious events.', + level: NagMessageLevel.ERROR, + rule: CloudWatchLogGroupRetentionPeriod, + node: node, + }); + + this.applyRule({ + info: 'The CloudWatch Log Group is not encrypted with an AWS KMS key - (Control IDs: MUST(16.6.12.C.01[CID:2022], 23.5.11.C.01[CID:7496]))', + explanation: + 'To help protect sensitive data at rest, ensure encryption is enabled for your Amazon CloudWatch Log Groups.', + level: NagMessageLevel.ERROR, + rule: CloudWatchLogGroupEncrypted, + node: node, + }); + } + + /** + * Check DMS Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkDMS(node: CfnResource) { + this.applyRule({ + info: 'The DMS replication instance is public - (Control IDs: MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]))', + explanation: + 'DMS replication instances can contain sensitive information and access control is required for such accounts.', + level: NagMessageLevel.ERROR, + rule: DMSReplicationNotPublic, + node: node, + }); + } + + /** + * Check DynamoDB Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkDynamoDB(node: CfnResource) { + this.applyRule({ + info: 'The provisioned capacity DynamoDB table does not have Auto Scaling enabled on its indexes - (Control IDs: MUST(22.1.23.C.01[CID:4829]))', + explanation: + 'Amazon DynamoDB auto scaling uses the AWS Application Auto Scaling service to adjust provisioned throughput capacity that automatically responds to actual traffic patterns. This enables a table or a global secondary index to increase its provisioned read/write capacity to handle sudden increases in traffic, without throttling.', + level: NagMessageLevel.ERROR, + rule: DynamoDBAutoScalingEnabled, + node: node, + }); + this.applyRule({ + info: 'The DynamoDB table is not in an AWS Backup plan - (Control IDs: MUST(22.1.26.C.01[CID:4849]))', + explanation: + 'To help with data back-up processes, ensure your Amazon DynamoDB tables are a part of an AWS Backup plan. AWS Backup is a fully managed backup service with a policy-based backup solution. This solution simplifies your backup management and enables you to meet your business and regulatory backup compliance requirements.', + level: NagMessageLevel.ERROR, + rule: DynamoDBInBackupPlan, + node: node, + }); + this.applyRule({ + info: 'The DynamoDB table does not have Point-in-time Recovery enabled - (Control IDs: MUST(22.1.26.C.01[CID:4849]))', + explanation: + 'The recovery maintains continuous backups of your table for the last 35 days.', + level: NagMessageLevel.ERROR, + rule: DynamoDBPITREnabled, + node: node, + }); + } + + /** + * Check EC2 Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkEC2(node: CfnResource): void { + this.applyRule({ + info: 'The EBS volume is not in an AWS Backup plan - (Control IDs: MUST(22.1.26.C.01[CID:4849]))', + explanation: + 'To help with data back-up processes, ensure your Amazon Elastic Block Store (Amazon EBS) volumes are a part of an AWS Backup plan. AWS Backup is a fully managed backup service with a policy-based backup solution. This solution simplifies your backup management and enables you to meet your business and regulatory backup compliance requirements.', + level: NagMessageLevel.ERROR, + rule: EC2EBSInBackupPlan, + node: node, + }); + + this.applyRule({ + info: 'The EC2 instance is associated with a public IP address - (Control IDs: MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]))', + explanation: + 'Manage access to the AWS Cloud by ensuring Amazon Elastic Compute Cloud (Amazon EC2) instances cannot be publicly accessed. Amazon EC2 instances can contain sensitive information and access control is required for such accounts.', + level: NagMessageLevel.ERROR, + rule: EC2InstanceNoPublicIp, + node: node, + }); + + this.applyRule({ + info: 'The EC2 instance is not within a VPC - (Control IDs: MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]))', + explanation: + '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.', + level: NagMessageLevel.ERROR, + rule: EC2InstancesInVPC, + node: node, + }); + + this.applyRule({ + info: 'The EBS volume has encryption disabled - (Control IDs: SHOULD(17.1.46.C.04[CID:2082], 22.1.24.C.04[CID:4839]))', + explanation: + 'With EBS encryption, you aren not 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: NagMessageLevel.WARN, + rule: EC2EBSVolumeEncrypted, + node: node, + }); + + this.applyRule({ + info: 'The Security Group allows unrestricted SSH access - (Control IDs: SHOULD(17.5.8.C.02[CID:2726]))', + explanation: + 'Not allowing ingress (or remote) traffic from 0.0.0.0/0 or ::/0 to port 22 on your resources helps to restrict remote access.', + level: NagMessageLevel.WARN, + rule: EC2RestrictedSSH, + node: node, + }); + + this.applyRule({ + info: 'The Security Group allows access other than tcp 443 - (Control IDs: SHOULD(18.1.13.C.02[CID:3205]))', + explanation: + 'Not allowing ingress (or remote) traffic to ports other than tcp port 443 helps improve security', + level: NagMessageLevel.WARN, + rule: EC2SecurityGroupOnlyTcp443, + node: node, + }); + + // this can be modified to use EC2IMDVs2 enabled. + this.applyRule({ + info: 'The EC2 Instance does not use IMDSv2 - (Control IDs: MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]))', + explanation: + 'IMDSv2 adds additional protection by using session authentication to the Instance Meta Data Service', + level: NagMessageLevel.ERROR, + rule: EC2IMDSv2Enabled, + node: node, + }); + } + + /** + * Check ECS Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkECS(node: CfnResource): void { + this.applyRule({ + info: '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 - (Control IDs: SHOULD(14.1.8.C.01[CID:1149]))', + explanation: + '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.', + level: NagMessageLevel.WARN, + rule: ECSTaskDefinitionUserForHostMode, + node: node, + }); + } + + /** + * Check EFS Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkEFS(node: CfnResource) { + this.applyRule({ + info: 'The EFS is not in an AWS Backup plan - (Control IDs: MUST(22.1.26.C.01[CID:4849]))', + explanation: + 'To help with data back-up processes, ensure your Amazon Elastic File System (Amazon EFS) file systems are a part of an AWS Backup plan. AWS Backup is a fully managed backup service with a policy-based backup solution. This solution simplifies your backup management and enables you to meet your business and regulatory backup compliance requirements.', + level: NagMessageLevel.ERROR, + rule: EFSInBackupPlan, + node: node, + }); + this.applyRule({ + info: 'The EFS does not have encryption at rest enabled - (Control IDs: SHOULD(17.1.46.C.04[CID:2082], 22.1.24.C.04[CID:4839]))', + explanation: + 'Because sensitive data can exist and to help protect data at rest, ensure encryption is enabled for your Amazon Elastic File System (EFS).', + level: NagMessageLevel.WARN, + rule: EFSEncrypted, + node: node, + }); + } + + /** + * Check ElastiCache Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkElastiCache(node: CfnResource) { + this.applyRule({ + info: 'The ElastiCache Redis cluster does not retain automatic backups for at least 15 days - (Control IDs: MUST(22.1.26.C.01[CID:4849]))', + 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.', + level: NagMessageLevel.ERROR, + rule: ElastiCacheRedisClusterAutomaticBackup, + node: node, + }); + } + + /** + * Check Elastic Beanstalk Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkElasticBeanstalk(node: CfnResource): void { + this.applyRule({ + info: 'The Elastic Beanstalk environment does not have enhanced health reporting enabled - (Control IDs: SHOULD(12.4.4.C.05[CID:3452]))', + explanation: + 'Enabling managed platform updates for an Amazon Elastic Beanstalk environment ensures that the latest available platform fixes, updates, and features for the environment are installed. Keeping up to date with patch installation is a best practice in securing systems.', + level: NagMessageLevel.WARN, + rule: ElasticBeanstalkManagedUpdatesEnabled, + node: node, + }); + } + + /** + * Check Elastic Load Balancer Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + + private checkELB(node: CfnResource): void { + this.applyRule({ + info: 'The ALBs HTTP listeners are not configured to redirect to HTTPS - (Control IDs: MUST(16.1.37.C.01[CID:1847], 17.1.48.C.03[CID:2091]))', + 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.', + level: NagMessageLevel.ERROR, + rule: ALBHttpToHttpsRedirection, + node: node, + }); + + this.applyRule({ + info: 'The ALB is not associated with AWS WAFv2 web ACL - (Control IDs: SHOULD(20.3.7.C.02[CID:4333]), MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]))', + explanation: + 'A WAF helps to protect your web applications or APIs against common web exploits. These web exploits may affect availability, compromise security, or consume excessive resources within your environment.', + level: NagMessageLevel.ERROR, + rule: ALBWAFEnabled, + node: node, + }); + + this.applyRule({ + info: 'Load Balancer is not enabled for Cross Zone - (Control IDs: MUST(22.1.23.C.01[CID:4829]))', + explanation: + "Enable cross-zone load balancing for your Classic Load Balancers (CLBs) to help maintain adequate capacity and availability. The cross-zone load balancing reduces the need to maintain equivalent numbers of instances in each enabled availability zone. It also improves your application's ability to handle the loss of one or more instances.", + level: NagMessageLevel.ERROR, + rule: ELBCrossZoneLoadBalancingEnabled, + node: node, + }); + + this.applyRule({ + info: 'The ELB does not have logging enabled - (Control IDs: SHOULD(16.6.10.C.02[CID:2013]), MUST(23.5.11.C.01[CID:7496]))', + 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.", + level: NagMessageLevel.ERROR, + rule: ELBLoggingEnabled, + node: node, + }); + this.applyRule({ + info: 'The ELB does not restrict its listeners to only the SSL and HTTPS protocol - (Control IDs: SHOULD(14.5.8.C.01[CID:1667], 22.1.24.C.04[CID:4839])), MUST(16.1.37.C.01[CID:1847], 17.1.48.C.03[CID:2091])) ', + explanation: + 'Ensure that your Classic Load Balancers (CLBs) are configured with SSL or HTTPS listeners. Because sensitive data can exist, enable encryption in transit to help protect that data.', + level: NagMessageLevel.ERROR, + rule: ELBTlsHttpsListenersOnly, + node: node, + }); + } + + /** + * Check IAM Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkIAM(node: CfnResource): void { + this.applyRule({ + info: 'The IAM policy grants admin access, meaning the policy allows a principal to perform all actions on all resources - (Control IDs: SHOULD(16.3.5.C.02[CID:1946]))', + explanation: + 'AWS Identity and Access Management (IAM) can help you incorporate the principles of least privilege and separation of duties with access permissions and authorizations, by ensuring that IAM groups have at least one IAM user. Placing IAM users in groups based on their associated permissions or job function is one way to incorporate least privilege.', + level: NagMessageLevel.WARN, + rule: IAMPolicyNoStatementsWithAdminAccess, + node: node, + }); + } + + /** + * Check KMS Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkKMS(node: CfnResource): void { + this.applyRule({ + info: 'The KMS Symmetric key does not have automatic key rotation enabled - (Control IDs: SHOULD(17.9.25.C.01[CID:3021]))', + explanation: + 'Enable key rotation to ensure that keys are rotated once they have reached the end of their crypto period.', + level: NagMessageLevel.WARN, + rule: KMSBackingKeyRotationEnabled, + node: node, + }); + } + + /** + * Check Lambda + * @param node + */ + + private checkLambda(node: CfnResource) { + this.applyRule({ + info: 'The Lambda function permission grants public access - (Control IDs: MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]))', + explanation: + 'Public access allows anyone on the internet to perform unauthenticated actions on your function and can potentially lead to degraded availability.', + level: NagMessageLevel.ERROR, + rule: LambdaFunctionPublicAccessProhibited, + node: node, + }); + } + + /** + * Check OpenSearch Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkOpenSearch(node: CfnResource) { + this.applyRule({ + info: 'The OpenSearch Service domain does not have encryption at rest enabled - (Control IDs: SHOULD(17.1.46.C.04[CID:2082], 20.4.4.C.02[CID:4441], 22.1.24.C.04[CID:4839]))', + explanation: + 'Because sensitive data can exist and to help protect data at rest, ensure encryption is enabled for your Amazon OpenSearch Service (OpenSearch Service) domains.', + level: NagMessageLevel.WARN, + rule: OpenSearchEncryptedAtRest, + node: node, + }); + + this.applyRule({ + info: 'The OpenSearch Service domain is not running within a VPC - (Control IDs: SHOULD(19.1.14.C.02[CID:3623]), MUST(19.1.12.C.01[CID:3562]))', + explanation: + 'VPCs help secure your AWS resources and provide an extra layer of protection.', + level: NagMessageLevel.ERROR, + rule: OpenSearchInVPCOnly, + node: node, + }); + + this.applyRule({ + info: 'The OpenSearch Service domain does not have node-to-node encryption enabled - (Control IDs: SHOULD(22.1.24.C.04[CID:4839]), MUST(16.1.37.C.01[CID:1847])) ', + explanation: + 'Because sensitive data can exist, enable encryption in transit to help protect that data within your Amazon OpenSearch Service (OpenSearch Service) domains.', + level: NagMessageLevel.ERROR, + rule: OpenSearchNodeToNodeEncryption, + node: node, + }); + } + + /** + * Check RDS Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkRDS(node: CfnResource): void { + this.applyRule({ + info: 'The RDS DB Instance or Aurora Cluster does not have deletion protection enabled - (Control IDs: MUST(22.1.26.C.01[CID:4849]))', + explanation: + 'Ensure Amazon Relational Database Service (Amazon RDS) instances and clusters have deletion protection enabled. Use deletion protection to prevent your Amazon RDS DB instances and clusters from being accidentally or maliciously deleted, which can lead to loss of availability for your applications.', + level: NagMessageLevel.ERROR, + rule: RDSInstanceDeletionProtectionEnabled, + node: node, + }); + + this.applyRule({ + info: 'The RDS DB Instance does not have multi-AZ support - (Control IDs: MUST(22.1.23.C.01[CID:4829]))', + explanation: + 'Ensure Amazon Relational Database Service (Amazon RDS) instances and clusters have deletion protection enabled. Use deletion protection to prevent your Amazon RDS DB instances and clusters from being accidentally or maliciously deleted, which can lead to loss of availability for your applications.', + level: NagMessageLevel.ERROR, + rule: RDSMultiAZSupport, + node: node, + }); + + this.applyRule({ + info: 'The RDS DB instance is not in an AWS Backup plan - (Control IDs: MUST(22.1.26.C.01[CID:4849]))', + explanation: + 'To help with data back-up processes, ensure your Amazon Relational Database Service (Amazon RDS) instances are a part of an AWS Backup plan. AWS Backup is a fully managed backup service with a policy-based backup solution. This solution simplifies your backup management and enables you to meet your business and regulatory backup compliance requirements.', + level: NagMessageLevel.ERROR, + rule: RDSInBackupPlan, + node: node, + }); + + this.applyRule({ + info: 'The RDS DB Instance allows public access - (Control IDs: SHOULD(19.1.14.C.02[CID:3623]), MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]))', + explanation: + 'Amazon RDS database instances can contain sensitive information, and principles and access control is required for such accounts.', + level: NagMessageLevel.ERROR, + rule: RDSInstancePublicAccess, + node: node, + }); + + this.applyRule({ + info: 'The non-Aurora RDS DB instance or Aurora cluster does not have all CloudWatch log types exported - (Control IDs: SHOULD(16.6.10.C.02[CID:2013], 20.4.4.C.02[CID:4441], 20.4.5.C.02[CID:4445]), MUST(23.5.11.C.01[CID:7496]))', + 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.' + + "This is a granular rule that returns individual findings that can be suppressed with 'appliesTo'. The findings are in the format 'LogExport::' for exported logs. Example: appliesTo: ['LogExport::audit'].", + level: NagMessageLevel.ERROR, + rule: RDSLoggingEnabled, + node: node, + }); + + this.applyRule({ + info: 'The RDS DB Instance or Aurora Cluster does not have storage encrypted - (Control IDs: SHOULD(17.1.46.C.04[CID:2082], 20.4.4.C.02[CID:4441], 22.1.24.C.04[CID:4839]))', + explanation: + 'Because sensitive data can exist at rest in Amazon RDS instances, enable encryption at rest to help protect that data.', + level: NagMessageLevel.WARN, + rule: RDSStorageEncrypted, + node: node, + }); + + this.applyRule({ + info: 'RDS DB Instance is not configured for minor patches - (Control IDs: SHOULD(12.4.4.C.05[CID:3452]))', + explanation: 'Provides automatic Patching in the Database', + level: NagMessageLevel.WARN, + rule: RDSAutomaticMinorVersionUpgradeEnabled, + node: node, + }); + } + + /** + * Check Redshift Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkRedshift(node: CfnResource): void { + this.applyRule({ + info: 'The Redshift cluster does not have automated snapshots enabled or the retention period is not between 1 and 35 days - (Control IDs: MUST(22.1.26.C.01[CID:4849]))', + explanation: + 'To help with data back-up processes, ensure your Amazon Redshift clusters have automated snapshots. When automated snapshots are enabled for a cluster, Redshift periodically takes snapshots of that cluster. By default, Redshift takes a snapshot every eight hours or every 5 GB per node of data changes, or whichever comes first.', + level: NagMessageLevel.ERROR, + rule: RedshiftBackupEnabled, + node: node, + }); + + this.applyRule({ + info: 'The Redshift cluster does not have encryption or audit logging enabled - (Control IDs: SHOULD(20.4.4.C.02[CID:4441], 20.4.5.C.02[CID:4445], 22.1.24.C.04[CID:4839]))', + explanation: + 'To protect data at rest, ensure that encryption is enabled for your Amazon Redshift clusters. You must also ensure that required configurations are deployed on Amazon Redshift clusters. The audit logging should be enabled to provide information about connections and user activities in the database.', + level: NagMessageLevel.WARN, + rule: RedshiftClusterConfiguration, + node: node, + }); + + this.applyRule({ + info: 'The Redshift cluster does not have version upgrades enabled, automated snapshot retention periods enabled, and an explicit maintenance window configure - (Control IDs: SHOULD(12.4.4.C.06[CID:3453]), MUST(12.4.4.C.02[CID:3449]))', + explanation: + 'Ensure that Amazon Redshift clusters have the preferred settings for your organization. Specifically, that they have preferred maintenance windows and automated snapshot retention periods for the database. ', + level: NagMessageLevel.ERROR, + rule: RedshiftClusterMaintenanceSettings, + node: node, + }); + + this.applyRule({ + info: 'The Redshift cluster is publicly accessible - (Control IDs: SHOULD(19.1.14.C.02[CID:3623]), MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]))', + explanation: + 'Amazon Redshift clusters can contain sensitive information and principles and access control is required for such accounts.', + level: NagMessageLevel.ERROR, + rule: RedshiftClusterPublicAccess, + node: node, + }); + + this.applyRule({ + info: 'The Redshift cluster does not require TLS/SSL encryption - (Control IDs: SHOULD(22.1.24.C.04[CID:4839]), MUST(17.1.48.C.03[CID:2091])).', + explanation: + 'Ensure that your Amazon Redshift clusters require TLS/SSL encryption to connect to SQL clients. Because sensitive data can exist, enable encryption in transit to help protect that data.', + level: NagMessageLevel.ERROR, + rule: RedshiftRequireTlsSSL, + node: node, + }); + } + + /** + * Check Amazon S3 Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkS3(node: CfnResource): void { + this.applyRule({ + info: 'The S3 bucket does not prohibit public access through bucket level settings - (Control IDs: SHOULD(22.1.24.C.03[CID:4838]))', + explanation: + 'Keep sensitive data safe from unauthorized remote users by preventing public access at the bucket level.', + level: NagMessageLevel.WARN, + rule: S3BucketLevelPublicAccessProhibited, + node: node, + }); + this.applyRule({ + info: 'The S3 Bucket or bucket policy does not require requests to use SSL - (Control IDs: SHOULD(22.1.24.C.04[CID:4839]))', + explanation: + 'To help protect data in transit, ensure that your Amazon Simple Storage Service (Amazon S3) buckets require requests to use Secure Socket Layer (SSL). Because sensitive data can exist, enable encryption in transit to help protect that data.', + level: NagMessageLevel.WARN, + rule: S3BucketSSLRequestsOnly, + node: node, + }); + this.applyRule({ + info: 'The S3 Buckets does not have server access logs enabled - (Control IDs: MUST(22.1.26.C.01[CID:4849]))', + explanation: + 'Amazon Simple Storage Service (Amazon S3) server access logging provides a method to monitor the network for potential cybersecurity events. The events are monitored by capturing detailed records for the requests that are made to an Amazon S3 bucket. Each access log record provides details about a single access request. The details include the requester, bucket name, request time, request action, response status, and an error code, if relevant.', + level: NagMessageLevel.ERROR, + rule: S3BucketLoggingEnabled, + node: node, + }); + + this.applyRule({ + info: 'The S3 Bucket does not prohibit public read access through its Block Public Access configurations and bucket ACLs - (Control IDs: SHOULD(22.1.24.C.03[CID:4838]))', + explanation: + 'The management of access should be consistent with the classification of the data.', + level: NagMessageLevel.WARN, + rule: S3BucketPublicReadProhibited, + node: node, + }); + this.applyRule({ + info: 'The S3 Bucket does not prohibit public write access through its Block Public Access configurations and bucket ACLs - (Control IDs: SHOULD(22.1.24.C.03[CID:4838]))', + explanation: + 'The management of access should be consistent with the classification of the data.', + level: NagMessageLevel.WARN, + rule: S3BucketPublicWriteProhibited, + node: node, + }); + this.applyRule({ + info: 'The S3 Bucket does not have versioning enabled - (Control IDs: MUST(22.1.26.C.01[CID:4849]))', + explanation: + 'Use versioning to preserve, retrieve, and restore every version of every object stored in your Amazon S3 bucket. Versioning helps you to easily recover from unintended user actions and application failures.', + level: NagMessageLevel.ERROR, + rule: S3BucketVersioningEnabled, + node: node, + }); + this.applyRule({ + info: 'The S3 Bucket is not encrypted with a KMS Key by default - (Control IDs: SHOULD(17.1.46.C.04[CID:2082]))', + explanation: + 'Ensure that encryption is enabled for your Amazon Simple Storage Service (Amazon S3) buckets. Because sensitive data can exist at rest in an Amazon S3 bucket, enable encryption at rest to help protect that data.', + level: NagMessageLevel.WARN, + rule: S3DefaultEncryptionKMS, + node: node, + }); + } + + /** + * Check SageMaker Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkSageMaker(node: CfnResource) { + this.applyRule({ + info: 'The SageMaker resource endpoint is not encrypted with a KMS key - (Control IDs: SHOULD(22.1.24.C.04[CID:4839]))', + explanation: + 'Because sensitive data can exist at rest in SageMaker endpoint, enable encryption at rest to help protect that data.', + level: NagMessageLevel.WARN, + rule: SageMakerEndpointConfigurationKMSKeyConfigured, + node: node, + }); + this.applyRule({ + info: 'The SageMaker notebook is not encrypted with a KMS key - (Control IDs: SHOULD(22.1.24.C.04[CID:4839]))', + explanation: + 'Because sensitive data can exist at rest in SageMaker notebook, enable encryption at rest to help protect that data.', + level: NagMessageLevel.WARN, + rule: SageMakerNotebookInstanceKMSKeyConfigured, + node: node, + }); + this.applyRule({ + info: 'The SageMaker notebook does not disable direct internet access - (Control IDs: MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]))', + explanation: + 'By preventing direct internet access, you can keep sensitive data from being accessed by unauthorized users.', + level: NagMessageLevel.ERROR, + rule: SageMakerNotebookNoDirectInternetAccess, + node: node, + }); + } + + /** + * Check Secrets Manager Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkSecretsManager(node: CfnResource): void { + this.applyRule({ + info: 'The secret is not encrypted with a KMS Customer managed key - (Control IDs: SHOULD(22.1.24.C.04[CID:4839]))', + explanation: + 'To help protect data at rest, ensure encryption with AWS Key Management Service (AWS KMS) is enabled for AWS Secrets Manager secrets. Because sensitive data can exist at rest in Secrets Manager secrets, enable encryption at rest to help protect that data.', + level: NagMessageLevel.WARN, + rule: SecretsManagerUsingKMSKey, + node: node, + }); + } + + /** + * Check Amazon SNS Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkSNS(node: CfnResource): void { + this.applyRule({ + info: 'The SNS topic does not have KMS encryption enabled - (Control IDs: SHOULD(22.1.24.C.04[CID:4839]))', + explanation: + 'To help protect data at rest, ensure that your Amazon Simple Notification Service (Amazon SNS) topics require encryption using AWS Key Management Service (AWS KMS) Because sensitive data can exist at rest in published messages, enable encryption at rest to help protect that data.', + level: NagMessageLevel.WARN, + rule: SNSEncryptedKMS, + node: node, + }); + } + + /** + * Check VPC Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkVPC(node: CfnResource): void { + this.applyRule({ + info: 'The VPCs default security group allows inbound or outbound traffic - (Control IDs: MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]))', + explanation: + 'Amazon Elastic Compute Cloud (Amazon EC2) security groups can help in the management of network access by providing stateful filtering of ingress and egress network traffic to AWS resources. Restricting all the traffic on the default security group helps in restricting remote access to your AWS resources.', + level: NagMessageLevel.ERROR, + rule: VPCDefaultSecurityGroupClosed, + node: node, + }); + this.applyRule({ + info: 'The VPC does not have an associated Flow Log - (Control IDs: MUST(19.1.12.C.01[CID:3562], 23.4.10.C.01[CID:7466]))', + explanation: + 'The VPC flow logs provide detailed records for information about the IP traffic going to and from network interfaces in your Amazon Virtual Private Cloud (Amazon VPC). By default, the flow log record includes values for the different components of the IP flow, including the source, destination, and protocol.', + level: NagMessageLevel.ERROR, + rule: VPCFlowLogsEnabled, + node: node, + }); + } + + /** + * Check WAF Resources + * @param node the CfnResource to check + * @param ignores list of ignores for the resource + */ + private checkWAF(node: CfnResource): void { + this.applyRule({ + info: 'The WAFv2 web ACL does not have logging enabled - (Control IDs: SHOULD(16.6.10.C.02[CID:2013]), MUST(23.5.11.C.01[CID:7496]))', + explanation: + 'AWS WAF logging provides detailed information about the traffic that is analyzed by your web ACL. The logs record the time that AWS WAF received the request from your AWS resource, information about the request, and an action for the rule that each request matched.', + level: NagMessageLevel.ERROR, + rule: WAFv2LoggingEnabled, + node: node, + }); + } +} diff --git a/src/rules/cloudfront/CloudFrontDefaultRootObjectConfigured.ts b/src/rules/cloudfront/CloudFrontDefaultRootObjectConfigured.ts new file mode 100644 index 0000000000..0342bd8f42 --- /dev/null +++ b/src/rules/cloudfront/CloudFrontDefaultRootObjectConfigured.ts @@ -0,0 +1,31 @@ +/* +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ +import { parse } from 'path'; +import { CfnResource, Stack } from 'aws-cdk-lib'; +import { CfnDistribution } from 'aws-cdk-lib/aws-cloudfront'; +import { NagRuleCompliance } from '../../nag-rules'; + +/** + * CloudFront distributions should have a default Root Object + * @param node the CfnResource to check + */ +export default Object.defineProperty( + (node: CfnResource): NagRuleCompliance => { + if (node instanceof CfnDistribution) { + const distributionConfig = Stack.of(node).resolve( + node.distributionConfig + ); + + if (distributionConfig.defaultRootObject == undefined) { + return NagRuleCompliance.NON_COMPLIANT; + } + return NagRuleCompliance.COMPLIANT; + } else { + return NagRuleCompliance.NOT_APPLICABLE; + } + }, + 'name', + { value: parse(__filename).name } +); diff --git a/src/rules/cloudfront/index.ts b/src/rules/cloudfront/index.ts index d67d528893..0734107174 100644 --- a/src/rules/cloudfront/index.ts +++ b/src/rules/cloudfront/index.ts @@ -8,3 +8,4 @@ export { default as CloudFrontDistributionHttpsViewerNoOutdatedSSL } from './Clo export { default as CloudFrontDistributionNoOutdatedSSL } from './CloudFrontDistributionNoOutdatedSSL'; export { default as CloudFrontDistributionS3OriginAccessIdentity } from './CloudFrontDistributionS3OriginAccessIdentity'; export { default as CloudFrontDistributionWAFIntegration } from './CloudFrontDistributionWAFIntegration'; +export { default as CloudFrontDefaultRootObjectConfigured } from './CloudFrontDefaultRootObjectConfigured'; diff --git a/src/rules/ec2/EC2SecurityGroupOnlyTcp443.ts b/src/rules/ec2/EC2SecurityGroupOnlyTcp443.ts new file mode 100644 index 0000000000..f5c86be48d --- /dev/null +++ b/src/rules/ec2/EC2SecurityGroupOnlyTcp443.ts @@ -0,0 +1,95 @@ +/* +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ +import { parse } from 'path'; +import { CfnResource, Stack } from 'aws-cdk-lib'; +import { CfnSecurityGroupIngress, CfnSecurityGroup } from 'aws-cdk-lib/aws-ec2'; +import { NagRuleCompliance, NagRules } from '../../nag-rules'; + +/** + * Security Groups only allow inbound access to traffic using TCP on port 443 + * @param node the CfnResource to check + */ +export default Object.defineProperty( + (node: CfnResource): NagRuleCompliance => { + if (node instanceof CfnSecurityGroup) { + const ingressRules = Stack.of(node).resolve(node.securityGroupIngress); + + if (ingressRules) { + for (const rule of ingressRules) { + const resolvedcidrIp = NagRules.resolveIfPrimitive( + node, + Stack.of(node).resolve(rule).cidrIp + ); + const resolvedcidrIpv6 = NagRules.resolveIfPrimitive( + node, + Stack.of(node).resolve(rule).cidrIpv6 + ); + + if (resolvedcidrIp) { + if (!resolvedcidrIp.includes('/0')) { + return NagRuleCompliance.COMPLIANT; + } + } + if (resolvedcidrIpv6) { + if (!resolvedcidrIpv6.includes('/0')) { + return NagRuleCompliance.COMPLIANT; + } + } + + const ipProtocol = NagRules.resolveIfPrimitive( + node, + Stack.of(node).resolve(rule).ipProtocol + ); + const toPort = NagRules.resolveIfPrimitive( + node, + Stack.of(node).resolve(rule).toPort + ); + + if (!toPort) { + return NagRuleCompliance.NON_COMPLIANT; + } + + if (!(toPort === 443 && ipProtocol === 'tcp')) { + return NagRuleCompliance.NON_COMPLIANT; + } + } + } + + return NagRuleCompliance.COMPLIANT; + } else if (node instanceof CfnSecurityGroupIngress) { + const resolvedcidrIp = NagRules.resolveIfPrimitive(node, node.cidrIp); + const resolvedcidrIpv6 = NagRules.resolveIfPrimitive(node, node.cidrIpv6); + + if (resolvedcidrIp) { + if (!resolvedcidrIp.includes('/0')) { + return NagRuleCompliance.COMPLIANT; + } + } + if (resolvedcidrIpv6) { + if (!resolvedcidrIpv6.includes('/0')) { + return NagRuleCompliance.COMPLIANT; + } + } + + const ipProtocol = NagRules.resolveIfPrimitive(node, node.ipProtocol); + const toPort = NagRules.resolveIfPrimitive(node, node.toPort); + + if (!toPort) { + return NagRuleCompliance.NON_COMPLIANT; + } + + if (!(toPort === 443 && ipProtocol === 'tcp')) { + return NagRuleCompliance.NON_COMPLIANT; + } + + return NagRuleCompliance.COMPLIANT; + } + + return NagRuleCompliance.NOT_APPLICABLE; + }, + + 'name', + { value: parse(__filename).name } +); diff --git a/src/rules/ec2/index.ts b/src/rules/ec2/index.ts index 277220b67a..6825df1a37 100644 --- a/src/rules/ec2/index.ts +++ b/src/rules/ec2/index.ts @@ -15,3 +15,4 @@ export { default as EC2RestrictedCommonPorts } from './EC2RestrictedCommonPorts' export { default as EC2RestrictedInbound } from './EC2RestrictedInbound'; export { default as EC2RestrictedSSH } from './EC2RestrictedSSH'; export { default as EC2SecurityGroupDescription } from './EC2SecurityGroupDescription'; +export { default as EC2SecurityGroupOnlyTcp443 } from './EC2SecurityGroupOnlyTcp443'; diff --git a/test/Packs.test.ts b/test/Packs.test.ts index b6de2d5614..a6b372e9d3 100644 --- a/test/Packs.test.ts +++ b/test/Packs.test.ts @@ -13,6 +13,7 @@ import { NIST80053R5Checks, NagMessageLevel, PCIDSS321Checks, + NZISM36Checks, } from '../src'; describe('Check NagPack Details', () => { @@ -625,4 +626,103 @@ describe('Check NagPack Details', () => { expect(pack.actualErrors.sort()).toEqual(expectedErrors.sort()); }); }); + describe('NZISM3.6', () => { + class NZISM36ChecksExtended extends NZISM36Checks { + actualWarnings = new Array(); + actualErrors = new Array(); + applyRule(params: IApplyRule): void { + const ruleSuffix = params.ruleSuffixOverride + ? params.ruleSuffixOverride + : params.rule.name; + const ruleId = `${pack.readPackName}-${ruleSuffix}`; + if (params.level === NagMessageLevel.WARN) { + this.actualWarnings.push(ruleId); + } else { + this.actualErrors.push(ruleId); + } + } + } + const pack = new NZISM36ChecksExtended(); + test('Pack Name is correct', () => { + expect(pack.readPackName).toStrictEqual('NZISM3.6'); + }); + test('Pack contains expected warning and error rules', () => { + const expectedWarnings = [ + 'NZISM3.6-EC2RestrictedSSH', + 'NZISM3.6-CloudFrontDefaultRootObjectConfigured', + 'NZISM3.6-CloudTrailEncryptionEnabled', + 'NZISM3.6-EC2EBSVolumeEncrypted', + 'NZISM3.6-EC2SecurityGroupOnlyTcp443', + 'NZISM3.6-ECSTaskDefinitionUserForHostMode', + 'NZISM3.6-EFSEncrypted', + 'NZISM3.6-ElasticBeanstalkManagedUpdatesEnabled', + 'NZISM3.6-IAMPolicyNoStatementsWithAdminAccess', + 'NZISM3.6-KMSBackingKeyRotationEnabled', + 'NZISM3.6-OpenSearchEncryptedAtRest', + 'NZISM3.6-RDSAutomaticMinorVersionUpgradeEnabled', + 'NZISM3.6-RDSStorageEncrypted', + 'NZISM3.6-S3BucketLevelPublicAccessProhibited', + 'NZISM3.6-S3BucketPublicReadProhibited', + 'NZISM3.6-S3BucketPublicWriteProhibited', + 'NZISM3.6-S3BucketSSLRequestsOnly', + 'NZISM3.6-S3DefaultEncryptionKMS', + 'NZISM3.6-SNSEncryptedKMS', + 'NZISM3.6-SageMakerEndpointConfigurationKMSKeyConfigured', + 'NZISM3.6-SageMakerNotebookInstanceKMSKeyConfigured', + 'NZISM3.6-SecretsManagerUsingKMSKey', + 'NZISM3.6-RedshiftClusterConfiguration', + ]; + + const expectedErrors = [ + 'NZISM3.6-ALBHttpToHttpsRedirection', + 'NZISM3.6-ALBWAFEnabled', + 'NZISM3.6-APIGWExecutionLoggingEnabled', + 'NZISM3.6-CloudFrontDistributionAccessLogging', + 'NZISM3.6-CloudFrontDistributionHttpsViewerNoOutdatedSSL', + 'NZISM3.6-CloudFrontDistributionWAFIntegration', + 'NZISM3.6-CloudTrailCloudWatchLogsEnabled', + 'NZISM3.6-CloudTrailLogFileValidationEnabled', + 'NZISM3.6-CloudWatchLogGroupEncrypted', + 'NZISM3.6-CloudWatchLogGroupRetentionPeriod', + 'NZISM3.6-DMSReplicationNotPublic', + 'NZISM3.6-DynamoDBAutoScalingEnabled', + 'NZISM3.6-DynamoDBInBackupPlan', + 'NZISM3.6-DynamoDBPITREnabled', + 'NZISM3.6-EC2EBSInBackupPlan', + 'NZISM3.6-EC2IMDSv2Enabled', + 'NZISM3.6-EC2InstanceNoPublicIp', + 'NZISM3.6-EC2InstancesInVPC', + 'NZISM3.6-EFSInBackupPlan', + 'NZISM3.6-ELBCrossZoneLoadBalancingEnabled', + 'NZISM3.6-ELBLoggingEnabled', + 'NZISM3.6-ELBTlsHttpsListenersOnly', + 'NZISM3.6-ElastiCacheRedisClusterAutomaticBackup', + 'NZISM3.6-LambdaFunctionPublicAccessProhibited', + 'NZISM3.6-OpenSearchInVPCOnly', + 'NZISM3.6-OpenSearchNodeToNodeEncryption', + 'NZISM3.6-RDSInBackupPlan', + 'NZISM3.6-RDSInstanceDeletionProtectionEnabled', + 'NZISM3.6-RDSInstancePublicAccess', + 'NZISM3.6-RDSLoggingEnabled', + 'NZISM3.6-RDSMultiAZSupport', + 'NZISM3.6-RedshiftBackupEnabled', + 'NZISM3.6-RedshiftClusterMaintenanceSettings', + 'NZISM3.6-RedshiftClusterPublicAccess', + 'NZISM3.6-RedshiftRequireTlsSSL', + 'NZISM3.6-S3BucketLoggingEnabled', + 'NZISM3.6-S3BucketVersioningEnabled', + 'NZISM3.6-SageMakerNotebookNoDirectInternetAccess', + 'NZISM3.6-VPCDefaultSecurityGroupClosed', + 'NZISM3.6-VPCFlowLogsEnabled', + 'NZISM3.6-WAFv2LoggingEnabled', + ]; + jest.spyOn(pack, 'applyRule'); + const stack = new Stack(); + Aspects.of(stack).add(pack); + new CfnResource(stack, 'rTestResource', { type: 'foo' }); + SynthUtils.synthesize(stack).messages; + expect(pack.actualWarnings.sort()).toEqual(expectedWarnings.sort()); + expect(pack.actualErrors.sort()).toEqual(expectedErrors.sort()); + }); + }); }); diff --git a/test/rules/CloudFront.test.ts b/test/rules/CloudFront.test.ts index bff5cd9a98..e4f70d7c7d 100644 --- a/test/rules/CloudFront.test.ts +++ b/test/rules/CloudFront.test.ts @@ -23,6 +23,7 @@ import { CloudFrontDistributionNoOutdatedSSL, CloudFrontDistributionS3OriginAccessIdentity, CloudFrontDistributionWAFIntegration, + CloudFrontDefaultRootObjectConfigured, } from '../../src/rules/cloudfront'; const testPack = new TestPack([ @@ -32,6 +33,7 @@ const testPack = new TestPack([ CloudFrontDistributionNoOutdatedSSL, CloudFrontDistributionS3OriginAccessIdentity, CloudFrontDistributionWAFIntegration, + CloudFrontDefaultRootObjectConfigured, ]); let stack: Stack; @@ -397,4 +399,29 @@ describe('Amazon CloudFront', () => { validateStack(stack, ruleId, TestType.COMPLIANCE); }); }); + + describe('CloudFrontDefaultRootObjectConfigured: CloudFront distributions require a default object', () => { + const ruleId = 'CloudFrontDefaultRootObjectConfigured'; + + // Non Compliance + test('Noncompliance ', () => { + new Distribution(stack, 'Distribution', { + defaultBehavior: { + origin: new S3Origin(new Bucket(stack, 'OriginBucket')), + }, + }); + validateStack(stack, ruleId, TestType.NON_COMPLIANCE); + }); + + // Compliance + test('Compliance', () => { + new Distribution(stack, 'Distribution', { + defaultBehavior: { + origin: new S3Origin(new Bucket(stack, 'OriginBucket')), + }, + defaultRootObject: 'index.html', + }); + validateStack(stack, ruleId, TestType.COMPLIANCE); + }); + }); }); diff --git a/test/rules/EC2.test.ts b/test/rules/EC2.test.ts index a08925be7c..1b2d4139a4 100644 --- a/test/rules/EC2.test.ts +++ b/test/rules/EC2.test.ts @@ -46,6 +46,7 @@ import { EC2RestrictedInbound, EC2RestrictedSSH, EC2SecurityGroupDescription, + EC2SecurityGroupOnlyTcp443, } from '../../src/rules/ec2'; const testPack = new TestPack([ @@ -62,6 +63,7 @@ const testPack = new TestPack([ EC2RestrictedInbound, EC2RestrictedSSH, EC2SecurityGroupDescription, + EC2SecurityGroupOnlyTcp443, ]); let stack: Stack; @@ -1163,3 +1165,158 @@ describe('Amazon Elastic Block Store (EBS)', () => { }); }); }); + +describe('EC2SecurityGroupOnlyTcp443: Security Groups should only allow TCP 443 from everything', () => { + const ruleId = 'EC2SecurityGroupOnlyTcp443'; + + test('a non compliant ipv6 rule', () => { + new CfnSecurityGroup(stack, 'SecurityGroup', { + groupDescription: 'security group tcp port 80 open on port 80', + securityGroupIngress: [ + { + toPort: 80, + ipProtocol: 'tcp', + cidrIpv6: '::0/0', + }, + ], + }); + validateStack(stack, ruleId, TestType.NON_COMPLIANCE); + }); + + test('a compliant ipv6 rule', () => { + new CfnSecurityGroup(stack, 'SecurityGroup', { + groupDescription: 'ipv6 to non ::0/0', + securityGroupIngress: [ + { + toPort: 80, + ipProtocol: 'tcp', + cidrIpv6: '2002::1234:abcd:ffff:c0a8:101/64', + }, + ], + }); + validateStack(stack, ruleId, TestType.COMPLIANCE); + }); + + test('no specified port', () => { + new CfnSecurityGroup(stack, 'SecurityGroup', { + groupDescription: 'security group tcp port 80 open', + securityGroupIngress: [ + { + ipProtocol: 'tcp', + cidrIp: '0.0.0.0/0', + }, + ], + }); + validateStack(stack, ruleId, TestType.NON_COMPLIANCE); + }); + + test('tcp port other than 443 from 0/0', () => { + new CfnSecurityGroup(stack, 'SecurityGroup', { + groupDescription: 'security group tcp port 80 open', + securityGroupIngress: [ + { + toPort: 80, + ipProtocol: 'tcp', + cidrIp: '0.0.0.0/0', + }, + ], + }); + validateStack(stack, ruleId, TestType.NON_COMPLIANCE); + }); + + test('udp port from 0/0', () => { + new CfnSecurityGroup(stack, 'SecurityGroup2', { + groupDescription: 'security group with udp port 53', + securityGroupIngress: [ + { + toPort: 53, + ipProtocol: 'udp', + cidrIp: '0.0.0.0/0', + }, + ], + }); + validateStack(stack, ruleId, TestType.NON_COMPLIANCE); + }); + + test('ipv4 tcp443 from anywhere', () => { + new CfnSecurityGroup(stack, 'SecurityGroup2', { + groupDescription: 'security group with tcp 443 ingress allowed', + securityGroupIngress: [ + { + toPort: 443, + ipProtocol: 'tcp', + cidrIp: '0.0.0.0/0', + }, + ], + }); + validateStack(stack, ruleId, TestType.COMPLIANCE); + }); + + test('tcp80 from 10/8', () => { + new CfnSecurityGroup(stack, 'SecurityGroup2', { + groupDescription: 'security group with tcp 443 ingress allowed', + securityGroupIngress: [ + { + toPort: 80, + ipProtocol: 'tcp', + cidrIp: '10.0.0.0/8', + }, + ], + }); + validateStack(stack, ruleId, TestType.COMPLIANCE); + }); + + test('ingressGroupCompliant', () => { + new CfnSecurityGroupIngress(stack, 'ingressGroup', { + ipProtocol: 'tcp', + toPort: 443, + cidrIp: '0.0.0.0/0', + }); + validateStack(stack, ruleId, TestType.COMPLIANCE); + }); + + test('ingressGroupNonCompliant', () => { + new CfnSecurityGroupIngress(stack, 'ingressGroup', { + ipProtocol: 'tcp', + toPort: 80, + cidrIp: '0.0.0.0/0', + }); + validateStack(stack, ruleId, TestType.NON_COMPLIANCE); + }); + + test('ingressGroupNonCompliant', () => { + new CfnSecurityGroupIngress(stack, 'ingressGroup', { + ipProtocol: 'tcp', + toPort: 443, + cidrIp: '10.0.0.0/8', + }); + validateStack(stack, ruleId, TestType.COMPLIANCE); + }); + + test('ingressgroup, ipv6 compliant', () => { + new CfnSecurityGroupIngress(stack, 'ingressGroup', { + ipProtocol: 'tcp', + toPort: 443, + cidrIpv6: '::/0', + }); + validateStack(stack, ruleId, TestType.COMPLIANCE); + }); + + test('ingressGroup, non compliant', () => { + new CfnSecurityGroupIngress(stack, 'ingressGroup', { + ipProtocol: 'tcp', + toPort: 80, + cidrIpv6: '::/0', + }); + validateStack(stack, ruleId, TestType.NON_COMPLIANCE); + }); + + test('ingressGroupnonopenCompliant', () => { + new CfnSecurityGroupIngress(stack, 'ingressGroup', { + ipProtocol: 'tcp', + toPort: 80, + cidrIpv6: 'FE80:CD00:0:CDE:1257:0:211E:729C/64', + }); + validateStack(stack, ruleId, TestType.COMPLIANCE); + }); +});