diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e0b10b4..e965e101 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +## v0.57 [2023-03-10] + +_Dependencies_ + +- AWS plugin `v0.95.0` or higher is now required. ([#579](https://github.com/turbot/steampipe-mod-aws-compliance/pull/579)) + +_What's new?_ + +- Added CIS Controls v8 IG1 benchmark (`steampipe check benchmark.cis_controls_v8_ig1`). ([#568](https://github.com/turbot/steampipe-mod-aws-compliance/pull/568)) +- Add 30 new controls to Other Compliance Checks benchmark. ([#563](https://github.com/turbot/steampipe-mod-aws-compliance/pull/563)) + +_Bug fixes_ + +- Fixed the `cloudtrail_multi_region_trail_enabled` query to correctly evaluate organizational trails. ([#552](https://github.com/turbot/steampipe-mod-aws-compliance/pull/552)) +- Fixed `s3_bucket_restrict_*` queries to correctly check if buckets prohibit public read access or not. ([#548](https://github.com/turbot/steampipe-mod-aws-compliance/pull/548)) +- Fixed `s3_bucket_acls_should_prohibit_user_access` query to correctly evaluate a bucket to be in `ok` state if it does not have ACLs for user access. ([#549](https://github.com/turbot/steampipe-mod-aws-compliance/pull/549)) + ## v0.56 [2023-02-03] _Bug fixes_ diff --git a/README.md b/README.md index 0f458620..e6a78267 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,12 @@ Or in a terminal: ![image](https://raw.githubusercontent.com/turbot/steampipe-mod-aws-compliance/main/docs/aws_cis_v140_console.png) Includes support for: +* [AWS CIS Controls v8 IG1](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.cis_controls_v8_ig1) 🚀 New! * [AWS CIS v1.2.0](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.cis_v120) 🚀 New! * [AWS CIS v1.3.0](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.cis_v130) * [AWS CIS v1.4.0](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.cis_v140) * [AWS CIS v1.5.0](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.cis_v150) +* [AWS Foundational Security Best Practices](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.foundational_security) * [Audit Manager Control Tower](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.control_tower) * [CISA Cyber Essentials](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.cisa_cyber_essentials) * [FedRAMP Low Revision 4](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.fedramp_low_rev_4) @@ -22,13 +24,12 @@ Includes support for: * [GxP 21 CFR Part 11](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.gxp_21_cfr_part_11) * [GxP EU Annex 11](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.gxp_eu_annex_11) * [HIPAA](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.hipaa) +* [NIST 800-171 Revision 2](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.nist_800_171_rev_2) * [NIST 800-53 Revision 4](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.nist_800_53_rev_4) * [NIST 800-53 Revision 5](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.nist_800_53_rev_5) -* [NIST 800-171 Revision 2](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.nist_800_171_rev_2) * [NIST Cybersecurity Framework (CSF)](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.nist_csf) * [Other Compliance Checks](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.other) * [PCI DSS v3.2.1](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.pci_v321) -* [AWS Foundational Security Best Practices](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.foundational_security) * [Reserve Bank of India (RBI) Cyber Security Framework](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.rbi_cyber_security) * [SOC 2](https://hub.steampipe.io/mods/turbot/aws_compliance/controls/benchmark.soc_2) diff --git a/cis_controls_v8_ig1/cis.sp b/cis_controls_v8_ig1/cis.sp new file mode 100644 index 00000000..234e9ef0 --- /dev/null +++ b/cis_controls_v8_ig1/cis.sp @@ -0,0 +1,30 @@ +locals { + cis_controls_v8_ig1_common_tags = merge(local.aws_compliance_common_tags, { + cis_controls_v8_ig1 = "true" + type = "Benchmark" + }) +} + +benchmark "cis_controls_v8_ig1" { + title = "CIS Controls v8 IG1" + description = "The CIS Critical Security Controls (CIS Controls) are a prioritized set of Safeguards to mitigate the most prevalent cyber-attacks against systems and networks. They are mapped to and referenced by multiple legal, regulatory, and policy frameworks." + documentation = file("./cis_controls_v8_ig1/docs/cis_overview.md") + children = [ + benchmark.cis_controls_v8_ig1_1, + benchmark.cis_controls_v8_ig1_3, + benchmark.cis_controls_v8_ig1_4, + benchmark.cis_controls_v8_ig1_5, + benchmark.cis_controls_v8_ig1_6, + benchmark.cis_controls_v8_ig1_7, + benchmark.cis_controls_v8_ig1_8, + benchmark.cis_controls_v8_ig1_10, + benchmark.cis_controls_v8_ig1_11, + benchmark.cis_controls_v8_ig1_12, + benchmark.cis_controls_v8_ig1_13, + benchmark.cis_controls_v8_ig1_16 + ] + + tags = merge(local.cis_controls_v8_ig1_common_tags, { + type = "Benchmark" + }) +} diff --git a/cis_controls_v8_ig1/cis_controls_v8_ig1_1.sp b/cis_controls_v8_ig1/cis_controls_v8_ig1_1.sp new file mode 100644 index 00000000..43799827 --- /dev/null +++ b/cis_controls_v8_ig1/cis_controls_v8_ig1_1.sp @@ -0,0 +1,34 @@ +benchmark "cis_controls_v8_ig1_1" { + title = "1 Inventory and Control of Enterprise Assets" + description = "Actively manage (inventory, track, and correct) all enterprise assets (end-user devices, including portable and mobile; network devices; non-computing/Internet of Things (IoT) devices; and servers) connected to the infrastructure physically, virtually, remotely, and those within cloud environments, to accurately know the totality of assets that need to be monitored and protected within the enterprise. This will also support identifying unauthorized and unmanaged assets to remove or remediate." + children = [ + benchmark.cis_controls_v8_ig1_1_1, + benchmark.cis_controls_v8_ig1_1_2 + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_1_1" { + title = "1.1 - Establish and Maintain Detailed Enterprise Asset Inventory" + description = "Establish and maintain an accurate, detailed, and up-to-date inventory of all enterprise assets with the potential to store or process data, to include: end-user devices (including portable and mobile), network devices, non-computing/IoT devices, and servers. Ensure the inventory records the network address (if static), hardware address, machine name, enterprise asset owner, department for each asset, and whether the asset has been approved to connect to the network. For mobile end-user devices, MDM type tools can support this process, where appropriate. This inventory includes assets connected to the infrastructure physically, virtually, remotely, and those within cloud environments. Additionally, it includes assets that are regularly connected to the enterprise’s network infrastructure, even if they are not under control of the enterprise. Review and update the inventory of all enterprise assets bi-annually, or more frequently." + children = [ + control.ec2_stopped_instance_30_days, + control.ssm_managed_instance_compliance_association_compliant, + control.vpc_eip_associated, + control.vpc_network_acl_unused, + control.vpc_security_group_associated_to_eni + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_1_2" { + title = "1.2 - Address Unauthorized Assets" + description = "Ensure that a process exists to address unauthorized assets on a weekly basis. The enterprise may choose to remove the asset from the network, deny the asset from connecting remotely to the network, or quarantine the asset." + children = [ + control.guardduty_enabled + ] + + tags = local.cis_controls_v8_ig1_common_tags +} diff --git a/cis_controls_v8_ig1/cis_controls_v8_ig1_10.sp b/cis_controls_v8_ig1/cis_controls_v8_ig1_10.sp new file mode 100644 index 00000000..30e3449d --- /dev/null +++ b/cis_controls_v8_ig1/cis_controls_v8_ig1_10.sp @@ -0,0 +1,30 @@ +benchmark "cis_controls_v8_ig1_10" { + title = "10 Malware Defenses" + description = "Prevent or control the installation, spread, and execution of malicious applications, code, or scripts on enterprise assets." + children = [ + benchmark.cis_controls_v8_ig1_10_1, + benchmark.cis_controls_v8_ig1_10_2 + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_10_1" { + title = "10.1 - Deploy and Maintain Anti-Malware Software" + description = "Deploy and maintain anti-malware software on all enterprise assets." + children = [ + control.guardduty_enabled + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_10_2" { + title = "10.2 - Configure Automatic Anti-Malware Signature Updates" + description = "Configure automatic updates for anti-malware signature files on all enterprise assets." + children = [ + control.guardduty_enabled + ] + + tags = local.cis_controls_v8_ig1_common_tags +} diff --git a/cis_controls_v8_ig1/cis_controls_v8_ig1_11.sp b/cis_controls_v8_ig1/cis_controls_v8_ig1_11.sp new file mode 100644 index 00000000..c7f17f61 --- /dev/null +++ b/cis_controls_v8_ig1/cis_controls_v8_ig1_11.sp @@ -0,0 +1,65 @@ +benchmark "cis_controls_v8_ig1_11" { + title = "11 Data Recovery" + description = "Establish and maintain data recovery practices sufficient to restore in-scope enterprise assets to a pre-incident and trusted state." + children = [ + benchmark.cis_controls_v8_ig1_11_2, + benchmark.cis_controls_v8_ig1_11_3, + benchmark.cis_controls_v8_ig1_11_4 + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_11_2" { + title = "11.2 - Perform Automated Backups" + description = "Perform automated backups of in-scope enterprise assets. Run backups weekly, or more frequently, based on the sensitivity of the data." + children = [ + control.dynamodb_table_in_backup_plan, + control.dynamodb_table_point_in_time_recovery_enabled, + control.ebs_volume_in_backup_plan, + control.ec2_instance_ebs_optimized, + control.efs_file_system_in_backup_plan, + control.elasticache_redis_cluster_automatic_backup_retention_15_days, + control.rds_db_instance_backup_enabled, + control.rds_db_instance_in_backup_plan, + control.redshift_cluster_automatic_snapshots_min_7_days, + control.redshift_cluster_maintenance_settings_check, + control.s3_bucket_cross_region_replication_enabled, + control.s3_bucket_versioning_enabled + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_11_3" { + title = "11.3 - Protect Recovery Data" + description = "Protect recovery data with equivalent controls to the original data. Reference encryption or data separation, based on requirements." + children = [ + control.ebs_volume_encryption_at_rest_enabled, + control.ec2_ebs_default_encryption_enabled, + control.rds_db_instance_encryption_at_rest_enabled, + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_11_4" { + title = "11.4 - Establish and Maintain an Isolated Instance of Recovery Data" + description = "Establish and maintain an isolated instance of recovery data. Example implementations include, version controlling backup destinations through offline, cloud, or off-site systems or services." + children = [ + control.dynamodb_table_in_backup_plan, + control.dynamodb_table_point_in_time_recovery_enabled, + control.ebs_volume_in_backup_plan, + control.ec2_instance_ebs_optimized, + control.efs_file_system_in_backup_plan, + control.elasticache_redis_cluster_automatic_backup_retention_15_days, + control.rds_db_instance_backup_enabled, + control.rds_db_instance_in_backup_plan, + control.redshift_cluster_automatic_snapshots_min_7_days, + control.redshift_cluster_maintenance_settings_check, + control.s3_bucket_cross_region_replication_enabled, + control.s3_bucket_versioning_enabled + ] + + tags = local.cis_controls_v8_ig1_common_tags +} diff --git a/cis_controls_v8_ig1/cis_controls_v8_ig1_12.sp b/cis_controls_v8_ig1/cis_controls_v8_ig1_12.sp new file mode 100644 index 00000000..b52ff0d9 --- /dev/null +++ b/cis_controls_v8_ig1/cis_controls_v8_ig1_12.sp @@ -0,0 +1,20 @@ +benchmark "cis_controls_v8_ig1_12" { + title = "12 Network Infrastructure Management" + description = "Establish, implement, and actively manage (track, report, correct) network devices, in order to prevent attackers from exploiting vulnerable network services and access points." + children = [ + benchmark.cis_controls_v8_ig1_12_1 + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_12_1" { + title = "12.1 - Ensure Network Infrastructure is Up-to-Date" + description = "Ensure network infrastructure is kept up-to-date. Example implementations include running the latest stable release of software and/or using currently supported network-as-a-service (NaaS) offerings. Review software versions monthly, or more frequently, to verify software support." + children = [ + control.ec2_instance_ssm_managed, + control.ssm_managed_instance_compliance_patch_compliant + ] + + tags = local.cis_controls_v8_ig1_common_tags +} diff --git a/cis_controls_v8_ig1/cis_controls_v8_ig1_13.sp b/cis_controls_v8_ig1/cis_controls_v8_ig1_13.sp new file mode 100644 index 00000000..7640c382 --- /dev/null +++ b/cis_controls_v8_ig1/cis_controls_v8_ig1_13.sp @@ -0,0 +1,41 @@ +benchmark "cis_controls_v8_ig1_13" { + title = "13 Network Monitoring and Defense" + description = "Operate processes and tooling to establish and maintain comprehensive network monitoring and defense against security threats across the enterprise’s network infrastructure and user base." + children = [ + benchmark.cis_controls_v8_ig1_13_1, + benchmark.cis_controls_v8_ig1_13_3, + benchmark.cis_controls_v8_ig1_13_6 + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_13_1" { + title = "13.1 - Perform Application Layer Filtering" + children = [ + control.apigateway_stage_use_waf_web_acl, + control.guardduty_enabled, + control.securityhub_enabled + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_13_3" { + title = "13.3 - Ensure Network Infrastructure is Up-to-Date" + children = [ + control.guardduty_enabled + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_13_6" { + title = "13.6 - Collect Network Traffic Flow Logs" + children = [ + control.vpc_flow_logs_enabled, + control.wafv2_web_acl_logging_enabled + ] + + tags = local.cis_controls_v8_ig1_common_tags +} \ No newline at end of file diff --git a/cis_controls_v8_ig1/cis_controls_v8_ig1_16.sp b/cis_controls_v8_ig1/cis_controls_v8_ig1_16.sp new file mode 100644 index 00000000..d7337931 --- /dev/null +++ b/cis_controls_v8_ig1/cis_controls_v8_ig1_16.sp @@ -0,0 +1,37 @@ +benchmark "cis_controls_v8_ig1_16" { + title = "16 Application Software Security" + description = "Manage the security life cycle of in-house developed, hosted, or acquired software to prevent, detect, and remediate security weaknesses before they can impact the enterprise." + children = [ + benchmark.cis_controls_v8_ig1_16_1, + benchmark.cis_controls_v8_ig1_16_12 + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_16_1" { + title = "16.1 - Establish and Maintain a Secure Application Development Process" + description = "Deploy and maintain anti-malware software on all enterprise assets." + children = [ + control.codebuild_project_artifact_encryption_enabled, + control.codebuild_project_environment_privileged_mode_disabled, + control.codebuild_project_logging_enabled, + control.codebuild_project_plaintext_env_variables_no_sensitive_aws_values, + control.codebuild_project_source_repo_oauth_configured + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_16_12" { + title = "16.12 - Implement Code-Level Security Checks" + children = [ + control.codebuild_project_artifact_encryption_enabled, + control.codebuild_project_environment_privileged_mode_disabled, + control.codebuild_project_logging_enabled, + control.codebuild_project_plaintext_env_variables_no_sensitive_aws_values, + control.codebuild_project_source_repo_oauth_configured + ] + + tags = local.cis_controls_v8_ig1_common_tags +} \ No newline at end of file diff --git a/cis_controls_v8_ig1/cis_controls_v8_ig1_3.sp b/cis_controls_v8_ig1/cis_controls_v8_ig1_3.sp new file mode 100644 index 00000000..3e19a3cc --- /dev/null +++ b/cis_controls_v8_ig1/cis_controls_v8_ig1_3.sp @@ -0,0 +1,63 @@ +benchmark "cis_controls_v8_ig1_3" { + title = "3 Data Protection" + description = "Develop processes and technical controls to identify, classify, securely handle, retain, and dispose of data." + children = [ + benchmark.cis_controls_v8_ig1_3_3, + benchmark.cis_controls_v8_ig1_3_4 + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_3_3" { + title = "3.3 - Configure Data Access Control Lists" + description = "Configure data access control lists based on a user’s need to know. Apply data access control lists, also known as access permissions, to local and remote file systems, databases, and applications." + children = [ + control.autoscaling_launch_config_public_ip_disabled, + control.cloudwatch_log_group_retention_period_365, + control.dms_replication_instance_not_publicly_accessible, + control.ebs_snapshot_not_publicly_restorable, + control.ec2_instance_iam_profile_attached, + control.ec2_instance_in_vpc, + control.ec2_instance_not_publicly_accessible, + control.ec2_instance_uses_imdsv2, + control.ecs_task_definition_user_for_host_mode_check, + control.eks_cluster_endpoint_restrict_public_access, + control.emr_cluster_kerberos_enabled, + control.emr_cluster_master_nodes_no_public_ip, + control.es_domain_in_vpc, + control.iam_all_policy_no_service_wild_card, + control.iam_group_not_empty, + control.iam_group_user_role_no_inline_policies, + control.iam_managed_policy_attached_to_role, + control.iam_policy_no_star_star, + control.iam_policy_unused, + control.iam_root_user_no_access_keys, + control.iam_user_in_group, + control.iam_user_no_inline_attached_policies, + control.lambda_function_in_vpc, + control.lambda_function_restrict_public_access, + control.rds_db_instance_prohibit_public_access, + control.rds_db_snapshot_prohibit_public_access, + control.redshift_cluster_prohibit_public_access, + control.s3_bucket_policy_restricts_cross_account_permission_changes, + control.s3_bucket_restrict_public_read_access, + control.s3_bucket_restrict_public_write_access, + control.s3_public_access_block_account, + control.s3_public_access_block_bucket, + control.sagemaker_notebook_instance_direct_internet_access_disabled, + control.vpc_subnet_auto_assign_public_ip_disabled + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_3_4" { + title = "3.4 - Enforce Data Retention" + description = "Retain data according to the enterprise’s data management process. Data retention must include both minimum and maximum timelines." + children = [ + control.cloudwatch_log_group_retention_period_365 + ] + + tags = local.cis_controls_v8_ig1_common_tags +} \ No newline at end of file diff --git a/cis_controls_v8_ig1/cis_controls_v8_ig1_4.sp b/cis_controls_v8_ig1/cis_controls_v8_ig1_4.sp new file mode 100644 index 00000000..9ccc2a99 --- /dev/null +++ b/cis_controls_v8_ig1/cis_controls_v8_ig1_4.sp @@ -0,0 +1,76 @@ +benchmark "cis_controls_v8_ig1_4" { + title = "4 Secure Configuration of Enterprise Assets and Software" + description = "Establish and maintain the secure configuration of enterprise assets (end-user devices, including portable and mobile; network devices; non-computing/IoT devices; and servers) and software (operating systems and applications)." + children = [ + benchmark.cis_controls_v8_ig1_4_1, + benchmark.cis_controls_v8_ig1_4_6, + benchmark.cis_controls_v8_ig1_4_7 + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_4_1" { + title = "4.1 - Establish and Maintain a Secure Configuration Process" + description = "Establish and maintain a secure configuration process for enterprise assets (end-user devices, including portable and mobile, non-computing/IoT devices, and servers) and software (operating systems and applications). Review and update documentation annually, or when significant enterprise changes occur that could impact this Safeguard." + children = [ + control.account_part_of_organizations, + control.cloudtrail_security_trail_enabled, + control.ebs_volume_unused, + control.ec2_stopped_instance_30_days, + control.redshift_cluster_maintenance_settings_check, + control.ssm_managed_instance_compliance_association_compliant + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_4_6" { + title = "4.6 - Securely Manage Enterprise Assets and Software" + description = "Securely manage enterprise assets and software. Example implementations include managing configuration through version-controlled-infrastructure-as-code and accessing administrative interfaces over secure network protocols, such as Secure Shell (SSH) and Hypertext Transfer Protocol Secure (HTTPS). Do not use insecure management protocols, such as Telnet (Teletype Network) and HTTP, unless operationally essential." + children = [ + control.account_part_of_organizations, + control.autoscaling_group_with_lb_use_health_check, + control.cloudtrail_multi_region_trail_enabled, + control.cloudtrail_s3_data_events_enabled, + control.cloudtrail_trail_integrated_with_logs, + control.cloudtrail_trail_logs_encrypted_with_kms_cmk, + control.cloudtrail_trail_validation_enabled, + control.ebs_volume_encryption_at_rest_enabled, + control.ec2_ebs_default_encryption_enabled, + control.ec2_instance_iam_profile_attached, + control.iam_account_password_policy_min_length_14, + control.iam_group_user_role_no_inline_policies, + control.iam_policy_no_star_star, + control.iam_root_user_hardware_mfa_enabled, + control.iam_root_user_mfa_enabled, + control.iam_root_user_no_access_keys, + control.iam_user_console_access_mfa_enabled, + control.iam_user_in_group, + control.iam_user_no_inline_attached_policies, + control.kms_cmk_rotation_enabled, + control.s3_bucket_cross_region_replication_enabled, + control.s3_bucket_default_encryption_enabled, + control.s3_bucket_enforces_ssl, + control.s3_bucket_logging_enabled, + control.s3_bucket_restrict_public_read_access, + control.s3_bucket_restrict_public_write_access, + control.s3_public_access_block_account, + control.vpc_default_security_group_restricts_all_traffic, + control.vpc_flow_logs_enabled, + control.vpc_security_group_restrict_ingress_ssh_all + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_4_7" { + title = "4.7 - Manage Default Accounts on Enterprise Assets and Software" + description = "Manage default accounts on enterprise assets and software, such as root, administrator, and other pre-configured vendor accounts. Example implementations can include: disabling default accounts or making them unusable." + children = [ + control.iam_root_user_mfa_enabled, + control.vpc_security_group_restrict_ingress_ssh_all + ] + + tags = local.cis_controls_v8_ig1_common_tags +} \ No newline at end of file diff --git a/cis_controls_v8_ig1/cis_controls_v8_ig1_5.sp b/cis_controls_v8_ig1/cis_controls_v8_ig1_5.sp new file mode 100644 index 00000000..8b67ad71 --- /dev/null +++ b/cis_controls_v8_ig1/cis_controls_v8_ig1_5.sp @@ -0,0 +1,45 @@ +benchmark "cis_controls_v8_ig1_5" { + title = "5 Account Management" + description = "Use processes and tools to assign and manage authorization to credentials for user accounts, including administrator accounts, as well as service accounts, to enterprise assets and software." + children = [ + benchmark.cis_controls_v8_ig1_5_2, + benchmark.cis_controls_v8_ig1_5_3, + benchmark.cis_controls_v8_ig1_5_4 + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_5_2" { + title = "5.2 - Use Unique Passwords" + description = "Use unique passwords for all enterprise assets. Best practice implementation includes, at a minimum, an 8-character password for accounts using MFA and a 14-character password for accounts not using MFA." + children = [ + control.iam_account_password_policy_min_length_14, + control.iam_root_user_mfa_enabled, + control.iam_user_console_access_mfa_enabled, + control.iam_user_mfa_enabled + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_5_3" { + title = "5.3 - Disable Dormant Accounts" + description = "Delete or disable any dormant accounts after a period of 45 days of inactivity, where supported." + children = [ + control.iam_user_unused_credentials_90 + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_5_4" { + title = "5.4 - Restrict Administrator Privileges to Dedicated Administrator Accounts" + description = "Restrict administrator privileges to dedicated administrator accounts on enterprise assets. Conduct general computing activities, such as internet browsing, email, and productivity suite use, from the user's primary, non-privileged account." + children = [ + control.iam_policy_no_star_star, + control.iam_root_user_no_access_keys + ] + + tags = local.cis_controls_v8_ig1_common_tags +} \ No newline at end of file diff --git a/cis_controls_v8_ig1/cis_controls_v8_ig1_6.sp b/cis_controls_v8_ig1/cis_controls_v8_ig1_6.sp new file mode 100644 index 00000000..38bdd83f --- /dev/null +++ b/cis_controls_v8_ig1/cis_controls_v8_ig1_6.sp @@ -0,0 +1,20 @@ +benchmark "cis_controls_v8_ig1_6" { + title = "6 Access Control Management" + description = "Use processes and tools to create, assign, manage, and revoke access credentials and privileges for user, administrator, and service accounts for enterprise assets and software." + children = [ + benchmark.cis_controls_v8_ig1_6_5, + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_6_5" { + title = "6.5 - Require MFA for Administrative Access" + description = "Require MFA for all administrative access accounts, where supported, on all enterprise assets, whether managed on-site or through a third-party provider." + children = [ + control.iam_root_user_mfa_enabled, + control.iam_user_console_access_mfa_enabled + ] + + tags = local.cis_controls_v8_ig1_common_tags +} \ No newline at end of file diff --git a/cis_controls_v8_ig1/cis_controls_v8_ig1_7.sp b/cis_controls_v8_ig1/cis_controls_v8_ig1_7.sp new file mode 100644 index 00000000..592ebbb5 --- /dev/null +++ b/cis_controls_v8_ig1/cis_controls_v8_ig1_7.sp @@ -0,0 +1,33 @@ +benchmark "cis_controls_v8_ig1_7" { + title = "7 Continuous Vulnerability Management" + description = "Develop a plan to continuously assess and track vulnerabilities on all enterprise assets within the enterprise’s infrastructure, in order to remediate, and minimize, the window of opportunity for attackers. Monitor public and private industry sources for new threat and vulnerability information." + children = [ + benchmark.cis_controls_v8_ig1_7_1, + benchmark.cis_controls_v8_ig1_7_3 + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_7_1" { + title = "7.1 - Establish and Maintain a Vulnerability Management Process" + description = "Establish and maintain a documented vulnerability management process for enterprise assets. Review and update documentation annually, or when significant enterprise changes occur that could impact this Safeguard." + children = [ + control.guardduty_enabled, + control.securityhub_enabled, + control.ssm_managed_instance_compliance_patch_compliant + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_7_3" { + title = "7.3 - Perform Automated Operating System Patch Management" + description = "Perform operating system updates on enterprise assets through automated patch management on a monthly, or more frequent, basis." + children = [ + control.redshift_cluster_maintenance_settings_check, + control.ssm_managed_instance_compliance_patch_compliant + ] + + tags = local.cis_controls_v8_ig1_common_tags +} diff --git a/cis_controls_v8_ig1/cis_controls_v8_ig1_8.sp b/cis_controls_v8_ig1/cis_controls_v8_ig1_8.sp new file mode 100644 index 00000000..aa7ca966 --- /dev/null +++ b/cis_controls_v8_ig1/cis_controls_v8_ig1_8.sp @@ -0,0 +1,42 @@ +benchmark "cis_controls_v8_ig1_8" { + title = "8 Audit Log Management" + description = "Collect, alert, review, and retain audit logs of events that could help detect, understand, or recover from an attack." + children = [ + benchmark.cis_controls_v8_ig1_8_1, + benchmark.cis_controls_v8_ig1_8_2 + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_8_1" { + title = "8.1 - Establish and Maintain an Audit Log Management Process" + description = "Establish and maintain an audit log management process that defines the enterprise’s logging requirements. At a minimum, address the collection, review, and retention of audit logs for enterprise assets. Review and update documentation annually, or when significant enterprise changes occur that could impact this Safeguard." + children = [ + control.cloudwatch_log_group_retention_period_365 + ] + + tags = local.cis_controls_v8_ig1_common_tags +} + +benchmark "cis_controls_v8_ig1_8_2" { + title = "8.2 - Collect Audit Logs" + description = "Collect audit logs. Ensure that logging, per the enterprise’s audit log management process, has been enabled across enterprise assets." + children = [ + control.apigateway_stage_logging_enabled, + control.cloudfront_distribution_logging_enabled, + control.cloudtrail_multi_region_trail_enabled, + control.cloudtrail_s3_data_events_enabled, + control.cloudtrail_trail_enabled, + control.cloudtrail_trail_integrated_with_logs, + control.elb_application_classic_lb_logging_enabled, + control.es_domain_logs_to_cloudwatch, + control.rds_db_instance_logging_enabled, + control.redshift_cluster_encryption_logging_enabled, + control.s3_bucket_logging_enabled, + control.vpc_flow_logs_enabled, + control.wafv2_web_acl_logging_enabled, + ] + + tags = local.cis_controls_v8_ig1_common_tags +} \ No newline at end of file diff --git a/cis_controls_v8_ig1/docs/cis_overview.md b/cis_controls_v8_ig1/docs/cis_overview.md new file mode 100644 index 00000000..e09a5e4c --- /dev/null +++ b/cis_controls_v8_ig1/docs/cis_overview.md @@ -0,0 +1,19 @@ +To obtain the latest version of the official guide, please visit https://www.cisecurity.org/controls/implementation-groups. + +## Overview + +The CIS Critical Security Controls® (CIS Controls®) started as a simple grassroots activity to identify the most common and important real-world cyber-attacks that affect enterprises every day, translate that knowledge and experience into positive, constructive action for defenders, and then share that information with a wider audience. The original goals were modest—to help people and enterprises focus their attention and get started on the most important steps to defend themselves from the attacks that really mattered. + +Led by the Center for Internet Security® (CIS®), the CIS Controls have matured into an international community of volunteer individuals and institutions that: +- Share insights into attacks and attackers, identify root causes, and translate that into classes of defensive action +- Create and share tools, working aids, and stories of adoption and problem-solving +- Map the CIS Controls to regulatory and compliance frameworks in order to ensure alignment and bring collective priority and focus to them +- Identify common problems and barriers (like initial assessment and implementation roadmaps), and solve them as a community + +The CIS Controls reflect the combined knowledge of experts from every part of the +ecosystem (companies, governments, individuals), with every role (threat responders +and analysts, technologists, information technology (IT) operators and defenders, +vulnerability-finders, tool makers, solution providers, users, policy-makers, auditors, +etc.), and across many sectors (government, power, defense, finance, transportation, +academia, consulting, security, IT, etc.), who have banded together to create, adopt, and +support the CIS Controls. \ No newline at end of file diff --git a/cis_v150/docs/cis_v150_4_12.md b/cis_v150/docs/cis_v150_4_12.md index 7c569ad6..1c9ca452 100644 --- a/cis_v150/docs/cis_v150_4_12.md +++ b/cis_v150/docs/cis_v150_4_12.md @@ -78,5 +78,5 @@ aws sns subscribe --topic-arn --protocol --no 4. Create an alarm that is associated with the CloudWatch Logs Metric Filter created in step 1 and an SNS topic created in step 2. ```bash -aws cloudwatch put-metric-alarm --alarm-name `` --metric-name `` --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluationperiods 1 --namespace 'CISBenchmark' --alarm-actions +aws cloudwatch put-metric-alarm --alarm-name `` --metric-name `` --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions ``` diff --git a/cis_v150/docs/cis_v150_4_15.md b/cis_v150/docs/cis_v150_4_15.md index 76f29667..f65668b6 100644 --- a/cis_v150/docs/cis_v150_4_15.md +++ b/cis_v150/docs/cis_v150_4_15.md @@ -78,5 +78,5 @@ aws sns subscribe --topic-arn --protocol --no 4. Create an alarm that is associated with the CloudWatch Logs Metric Filter created in step 1 and an SNS topic created in step 2. ```bash -aws cloudwatch put-metric-alarm --alarm-name `` --metric-name `` --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions +aws cloudwatch put-metric-alarm --alarm-name `` --metric-name `` --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions ``` diff --git a/cis_v150/docs/cis_v150_4_2.md b/cis_v150/docs/cis_v150_4_2.md index 299935df..27d69586 100644 --- a/cis_v150/docs/cis_v150_4_2.md +++ b/cis_v150/docs/cis_v150_4_2.md @@ -81,5 +81,5 @@ aws sns subscribe --topic-arn --protocol --no 4. Create an alarm that is associated with the CloudWatch Logs Metric Filter created in step 1 and an SNS topic created in step 2. ```bash -aws cloudwatch put-metric-alarm --alarm-name `` --metric-name `` --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace `CISBenchmark` --alarm-actions `` +aws cloudwatch put-metric-alarm --alarm-name `` --metric-name `` --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace `CISBenchmark` --alarm-actions `` ``` diff --git a/conformance_pack/apigateway.sp b/conformance_pack/apigateway.sp index f6b6dd37..d8454cd1 100644 --- a/conformance_pack/apigateway.sp +++ b/conformance_pack/apigateway.sp @@ -29,6 +29,7 @@ control "apigateway_stage_logging_enabled" { query = query.apigateway_stage_logging_enabled tags = merge(local.conformance_pack_apigateway_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" diff --git a/conformance_pack/autoscaling.sp b/conformance_pack/autoscaling.sp index 9f3e3d8c..c05d59d7 100644 --- a/conformance_pack/autoscaling.sp +++ b/conformance_pack/autoscaling.sp @@ -10,6 +10,7 @@ control "autoscaling_group_with_lb_use_health_check" { query = query.autoscaling_group_with_lb_use_health_check tags = merge(local.conformance_pack_autoscaling_common_tags, { + cis_controls_v8_ig1 = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" ffiec = "true" @@ -27,6 +28,7 @@ control "autoscaling_launch_config_public_ip_disabled" { query = query.autoscaling_launch_config_public_ip_disabled tags = merge(local.conformance_pack_autoscaling_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" diff --git a/conformance_pack/cloudformation.sp b/conformance_pack/cloudformation.sp index b02a8a2a..d0fe2133 100644 --- a/conformance_pack/cloudformation.sp +++ b/conformance_pack/cloudformation.sp @@ -34,3 +34,12 @@ control "cloudformation_stack_rollback_enabled" { }) } +control "cloudformation_stack_termination_protection_enabled" { + title = "Cloudformation stacks termination protection should be enabled" + description = "Ensure that Amazon CloudFormation stacks have termination protection feature enabled in order to protect them from being accidentally deleted. The safety feature can be enabled when you create the CloudFormation stack or for existing stacks using the AWS API (UpdateTerminationProtection command)." + query = query.cloudformation_stack_termination_protection_enabled + + tags = merge(local.conformance_pack_cloudformation_common_tags, { + other_checks = "true" + }) +} diff --git a/conformance_pack/cloudfront.sp b/conformance_pack/cloudfront.sp index 3b034430..37025729 100644 --- a/conformance_pack/cloudfront.sp +++ b/conformance_pack/cloudfront.sp @@ -24,3 +24,33 @@ control "cloudfront_distribution_geo_restrictions_enabled" { other_checks = "true" }) } + +control "cloudfront_distribution_use_secure_cipher" { + title = "CloudFront distributions should use secure SSL cipher" + description = "Ensure that CloudFront distributions do not have any insecure SSL ciphers. Using insecure and deprecated ciphers could make the SSL connection between the CloudFront and the origins vulnerable to exploits." + query = query.cloudfront_distribution_use_secure_cipher + + tags = merge(local.conformance_pack_cloudfront_common_tags, { + other_checks = "true" + }) +} + +control "cloudfront_distribution_non_s3_origins_encryption_in_transit_enabled" { + title = "CloudFront distributions should encrypt traffic to non S3 origins" + description = "This control ensures that conection between cloudfront and oriign server is encrypted. It is recommended to enforce HTTPS-only traffic between a CloudFront distribution and the origin." + query = query.cloudfront_distribution_non_s3_origins_encryption_in_transit_enabled + + tags = merge(local.conformance_pack_cloudfront_common_tags, { + other_checks = "true" + }) +} + +control "cloudfront_distribution_logging_enabled" { + title = "CloudFront distributions access logs should be enabled" + description = "This control checks if Amazon CloudFront distributions are configured to capture information from Amazon Simple Storage Service (Amazon S3) server access logs. This rule is non compliant if a CloudFront distribution does not have logging configured." + query = query.cloudfront_distribution_logging_enabled + + tags = merge(local.conformance_pack_cloudfront_common_tags, { + cis_controls_v8_ig1 = "true" + }) +} diff --git a/conformance_pack/cloudtrail.sp b/conformance_pack/cloudtrail.sp index c2f9ff4b..6611a0b5 100644 --- a/conformance_pack/cloudtrail.sp +++ b/conformance_pack/cloudtrail.sp @@ -10,6 +10,7 @@ control "cloudtrail_trail_integrated_with_logs" { query = query.cloudtrail_trail_integrated_with_logs tags = merge(local.conformance_pack_cloudtrail_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -32,6 +33,7 @@ control "cloudtrail_s3_data_events_enabled" { query = query.cloudtrail_s3_data_events_enabled tags = merge(local.conformance_pack_cloudtrail_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -55,6 +57,7 @@ control "cloudtrail_trail_logs_encrypted_with_kms_cmk" { query = query.cloudtrail_trail_logs_encrypted_with_kms_cmk tags = merge(local.conformance_pack_cloudtrail_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -76,6 +79,7 @@ control "cloudtrail_multi_region_trail_enabled" { query = query.cloudtrail_multi_region_trail_enabled tags = merge(local.conformance_pack_cloudtrail_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -98,6 +102,7 @@ control "cloudtrail_trail_validation_enabled" { query = query.cloudtrail_trail_validation_enabled tags = merge(local.conformance_pack_cloudtrail_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -117,6 +122,7 @@ control "cloudtrail_trail_enabled" { query = query.cloudtrail_trail_enabled tags = merge(local.conformance_pack_cloudtrail_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -139,10 +145,11 @@ control "cloudtrail_security_trail_enabled" { query = query.cloudtrail_security_trail_enabled tags = merge(local.conformance_pack_cloudtrail_common_tags, { - gdpr = "true" - nist_800_171_rev_2 = "true" - nist_800_53_rev_4 = "true" - soc_2 = "true" + cis_controls_v8_ig1 = "true" + gdpr = "true" + nist_800_171_rev_2 = "true" + nist_800_53_rev_4 = "true" + soc_2 = "true" }) } diff --git a/conformance_pack/cloudwatch.sp b/conformance_pack/cloudwatch.sp index 03977a36..f7e62b87 100644 --- a/conformance_pack/cloudwatch.sp +++ b/conformance_pack/cloudwatch.sp @@ -22,6 +22,16 @@ control "cloudwatch_alarm_action_enabled" { }) } +control "cloudwatch_cross_account_sharing" { + title = "CloudWatch should not allow cross-account sharing" + description = "Ensure that your Amazon CloudWatch is configured to allow access only to friendly AWS accounts in order to prevent unauthorized users from sharing their CloudWatch events." + query = query.cloudwatch_cross_account_sharing + + tags = merge(local.conformance_pack_cloudwatch_common_tags, { + other_checks = "true" + }) +} + control "log_group_encryption_at_rest_enabled" { title = "Log group encryption at rest should be enabled" description = "To help protect sensitive data at rest, ensure encryption is enabled for your Amazon CloudWatch Log Group" @@ -50,6 +60,7 @@ control "cloudwatch_log_group_retention_period_365" { query = query.cloudwatch_log_group_retention_period_365 tags = merge(local.conformance_pack_cloudwatch_common_tags, { + cis_controls_v8_ig1 = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" ffiec = "true" diff --git a/conformance_pack/codebuild.sp b/conformance_pack/codebuild.sp index d4b98014..ab7eccf6 100644 --- a/conformance_pack/codebuild.sp +++ b/conformance_pack/codebuild.sp @@ -4,12 +4,23 @@ locals { }) } +control "codebuild_project_build_greater_then_90_days" { + title = "CodeBuild projects should not be unused for 90 days or greater" + description = "Ensure CodeBuild projects are curently in use. It is recommended to remove the stale ones." + query = query.codebuild_project_build_greater_then_90_days + + tags = merge(local.conformance_pack_ecs_common_tags, { + other_checks = "true" + }) +} + control "codebuild_project_plaintext_env_variables_no_sensitive_aws_values" { title = "CodeBuild project plaintext environment variables should not contain sensitive AWS values" description = "Ensure authentication credentials AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY do not exist within AWS CodeBuild project environments. Do not store these variables in clear text. Storing these variables in clear text leads to unintended data exposure and unauthorized access." query = query.codebuild_project_plaintext_env_variables_no_sensitive_aws_values tags = merge(local.conformance_pack_codebuild_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -27,6 +38,7 @@ control "codebuild_project_source_repo_oauth_configured" { query = query.codebuild_project_source_repo_oauth_configured tags = merge(local.conformance_pack_codebuild_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -37,3 +49,43 @@ control "codebuild_project_source_repo_oauth_configured" { soc_2 = "true" }) } + +control "codebuild_project_with_user_controlled_buildspec" { + title = "CodeBuild projects should not use an user controlled buildspec" + description = "This control checks if buildspec.yml is used from a trusted source which user cant interfere with." + query = query.codebuild_project_with_user_controlled_buildspec + + tags = merge(local.conformance_pack_ecs_common_tags, { + other_checks = "true" + }) +} + +control "codebuild_project_logging_enabled" { + title = "CodeBuild project logging should be enabled" + description = "This control checks if an AWS CodeBuild project environment has at least one log option enabled. The rule is non compliant if the status of all present log configurations is set to 'DISABLED'." + query = query.codebuild_project_logging_enabled + + tags = merge(local.conformance_pack_codebuild_common_tags, { + cis_controls_v8_ig1 = "true" + }) +} + +control "codebuild_project_environment_privileged_mode_disabled" { + title = "CodeBuild project environment privileged mode should be disabled" + description = "This control checks if an AWS CodeBuild project environment has privileged mode enabled. The rule is non compliant for a CodeBuild project if ‘privilegedMode’ is set to ‘true’." + query = query.codebuild_project_environment_privileged_mode_disabled + + tags = merge(local.conformance_pack_codebuild_common_tags, { + cis_controls_v8_ig1 = "true" + }) +} + +control "codebuild_project_artifact_encryption_enabled" { + title = "CodeBuild project artifact encryption should be enabled" + description = "This control checks if an AWS CodeBuild project has encryption enabled for all of its artifacts. The rule is non compliant if 'encryptionDisabled' is set to 'true' for any primary or secondary (if present) artifact configurations." + query = query.codebuild_project_artifact_encryption_enabled + + tags = merge(local.conformance_pack_codebuild_common_tags, { + cis_controls_v8_ig1 = "true" + }) +} diff --git a/conformance_pack/dms.sp b/conformance_pack/dms.sp index d7728317..25dc70d1 100644 --- a/conformance_pack/dms.sp +++ b/conformance_pack/dms.sp @@ -10,6 +10,7 @@ control "dms_replication_instance_not_publicly_accessible" { query = query.dms_replication_instance_not_publicly_accessible tags = merge(local.conformance_pack_dms_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" diff --git a/conformance_pack/dynamodb.sp b/conformance_pack/dynamodb.sp index fcbe9404..75f6563d 100644 --- a/conformance_pack/dynamodb.sp +++ b/conformance_pack/dynamodb.sp @@ -29,6 +29,7 @@ control "dynamodb_table_point_in_time_recovery_enabled" { query = query.dynamodb_table_point_in_time_recovery_enabled tags = merge(local.conformance_pack_dynamodb_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -69,6 +70,7 @@ control "dynamodb_table_in_backup_plan" { query = query.dynamodb_table_in_backup_plan tags = merge(local.conformance_pack_dynamodb_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" ffiec = "true" gxp_21_cfr_part_11 = "true" diff --git a/conformance_pack/ebs.sp b/conformance_pack/ebs.sp index 46604075..6abfed02 100644 --- a/conformance_pack/ebs.sp +++ b/conformance_pack/ebs.sp @@ -10,6 +10,7 @@ control "ebs_snapshot_not_publicly_restorable" { query = query.ebs_snapshot_not_publicly_restorable tags = merge(local.conformance_pack_ebs_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -30,6 +31,7 @@ control "ebs_volume_encryption_at_rest_enabled" { query = query.ebs_volume_encryption_at_rest_enabled tags = merge(local.conformance_pack_ebs_common_tags, { + cis_controls_v8_ig1 = "true" fedramp_moderate_rev_4 = "true" gdpr = "true" gxp_eu_annex_11 = "true" @@ -67,6 +69,7 @@ control "ebs_volume_in_backup_plan" { query = query.ebs_volume_in_backup_plan tags = merge(local.conformance_pack_ebs_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" ffiec = "true" gxp_21_cfr_part_11 = "true" @@ -119,6 +122,7 @@ control "ebs_volume_unused" { query = query.ebs_volume_unused tags = merge(local.conformance_pack_ebs_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" diff --git a/conformance_pack/ec2.sp b/conformance_pack/ec2.sp index d84ca94d..62cf4ee7 100644 --- a/conformance_pack/ec2.sp +++ b/conformance_pack/ec2.sp @@ -10,6 +10,7 @@ control "ec2_ebs_default_encryption_enabled" { query = query.ec2_ebs_default_encryption_enabled tags = merge(local.conformance_pack_ec2_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" ffiec = "true" gxp_21_cfr_part_11 = "true" @@ -41,6 +42,7 @@ control "ec2_instance_in_vpc" { query = query.ec2_instance_in_vpc tags = merge(local.conformance_pack_ec2_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -61,6 +63,7 @@ control "ec2_instance_not_publicly_accessible" { query = query.ec2_instance_not_publicly_accessible tags = merge(local.conformance_pack_ec2_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -76,12 +79,23 @@ control "ec2_instance_not_publicly_accessible" { }) } +control "ec2_instance_no_high_level_finding_in_inspector_scan" { + title = "EC2 instances high level findings should not be there in inspector scans" + description = "Amazon Inspector scans operating system packages installed on your Amazon EC2 instances for vulnerabilities and network reachability issues. Each finding has the name of the detected vulnerability and provides a severity rating, information about the affected resource, and details such as how to remediate the reported vulnerability." + query = query.ec2_instance_no_high_level_finding_in_inspector_scan + + tags = merge(local.conformance_pack_ec2_common_tags, { + other_checks = "true" + }) +} + control "ec2_stopped_instance_30_days" { title = "EC2 stopped instances should be removed in 30 days" description = "Enable this rule to help with the baseline configuration of Amazon Elastic Compute Cloud (Amazon EC2) instances by checking whether Amazon EC2 instances have been stopped for more than the allowed number of days, according to your organization's standards." query = query.ec2_stopped_instance_30_days tags = merge(local.conformance_pack_ec2_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -101,6 +115,7 @@ control "ec2_instance_ebs_optimized" { tags = merge(local.conformance_pack_ec2_common_tags, { audit_manager_control_tower = "true" + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -120,6 +135,7 @@ control "ec2_instance_uses_imdsv2" { query = query.ec2_instance_uses_imdsv2 tags = merge(local.conformance_pack_ec2_common_tags, { + cis_controls_v8_ig1 = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" gxp_21_cfr_part_11 = "true" @@ -152,10 +168,11 @@ control "ec2_instance_iam_profile_attached" { query = query.ec2_instance_iam_profile_attached tags = merge(local.conformance_pack_ec2_common_tags, { - ffiec = "true" - gxp_21_cfr_part_11 = "true" - nist_800_171_rev_2 = "true" - nist_800_53_rev_5 = "true" + cis_controls_v8_ig1 = "true" + ffiec = "true" + gxp_21_cfr_part_11 = "true" + nist_800_171_rev_2 = "true" + nist_800_53_rev_5 = "true" }) } diff --git a/conformance_pack/ecs.sp b/conformance_pack/ecs.sp index 56e5b66d..bc4a35f4 100644 --- a/conformance_pack/ecs.sp +++ b/conformance_pack/ecs.sp @@ -4,12 +4,53 @@ locals { }) } +control "ecs_cluster_encryption_at_rest_enabled" { + title = "ECS clusters encryption at rest should be enabled" + description = "This control checks whether ECS Clustes have encryption at rest enabled. The check fails if encryption at rest is not enabled as sensitive data should be protected." + query = query.ecs_cluster_encryption_at_rest_enabled + + tags = merge(local.conformance_pack_ecs_common_tags, { + other_checks = "true" + }) +} + +control "ecs_cluster_instance_in_vpc" { + title = "ECS cluster instances should be in a VPC" + description = "Deploy AWS ECS cluster instance within an Amazon Virtual Private Cloud (Amazon VPC) for a secure communication between a instance and other services within the Amazon VPC." + query = query.ecs_cluster_instance_in_vpc + + tags = merge(local.conformance_pack_ecs_common_tags, { + other_checks = "true" + }) +} + +control "ecs_cluster_no_registered_container_instance" { + title = "At least one instance should be registered with ECS cluster" + description = "This control ensures that at least one container instance is registered with an ECS cluster." + query = query.ecs_cluster_no_registered_container_instance + + tags = merge(local.conformance_pack_ecs_common_tags, { + other_checks = "true" + }) +} + +control "ecs_service_load_balancer_attached" { + title = "ECS services should be attached to a load balancer" + description = "ECS service can be configured to use Elastic Load Balancing to distribute traffic evenly across the tasks in your service. It is recommended to use Application Load Balancers for your Amazon ECS services so that you can take advantage of these latest features, unless your service requires a feature that is only available with Network Load Balancers or Classic Load Balancers." + query = query.ecs_service_load_balancer_attached + + tags = merge(local.conformance_pack_ecs_common_tags, { + other_checks = "true" + }) +} + control "ecs_task_definition_user_for_host_mode_check" { title = "ECS task definition container definitions should be checked for host mode" - description = "Check if Amazon Elastic Container Service (Amazon ECS) task definition with host networking mode has 'privileged' or 'user' container definitions.The rule is NON_COMPLIANT for task definitions with host network mode and container definitions of privileged=false or empty and user=root or empty." + description = "Check if Amazon Elastic Container Service (Amazon ECS) task definition with host networking mode has 'privileged' or 'user' container definitions.The rule is non compliant for task definitions with host network mode and container definitions of privileged=false or empty and user=root or empty." query = query.ecs_task_definition_user_for_host_mode_check tags = merge(local.conformance_pack_ecs_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" diff --git a/conformance_pack/efs.sp b/conformance_pack/efs.sp index 560308a0..ac88e23b 100644 --- a/conformance_pack/efs.sp +++ b/conformance_pack/efs.sp @@ -29,16 +29,17 @@ control "efs_file_system_in_backup_plan" { query = query.efs_file_system_automatic_backups_enabled tags = merge(local.conformance_pack_efs_common_tags, { - ffiec = "true" - gxp_21_cfr_part_11 = "true" - gxp_eu_annex_11 = "true" - hipaa = "true" - nist_800_171_rev_2 = "true" - nist_800_53_rev_4 = "true" - nist_800_53_rev_5 = "true" - nist_csf = "true" - rbi_cyber_security = "true" - soc_2 = "true" + cis_controls_v8_ig1 = "true" + ffiec = "true" + gxp_21_cfr_part_11 = "true" + gxp_eu_annex_11 = "true" + hipaa = "true" + nist_800_171_rev_2 = "true" + nist_800_53_rev_4 = "true" + nist_800_53_rev_5 = "true" + nist_csf = "true" + rbi_cyber_security = "true" + soc_2 = "true" }) } diff --git a/conformance_pack/eks.sp b/conformance_pack/eks.sp index d6ee9bf4..32fccca6 100644 --- a/conformance_pack/eks.sp +++ b/conformance_pack/eks.sp @@ -21,8 +21,9 @@ control "eks_cluster_endpoint_restrict_public_access" { query = query.eks_cluster_endpoint_restrict_public_access tags = merge(local.conformance_pack_eks_common_tags, { - nist_800_171_rev_2 = "true" - nist_csf = "true" + cis_controls_v8_ig1 = "true" + nist_800_171_rev_2 = "true" + nist_csf = "true" }) } diff --git a/conformance_pack/elasticache.sp b/conformance_pack/elasticache.sp index 9fd367ff..0b8f96e5 100644 --- a/conformance_pack/elasticache.sp +++ b/conformance_pack/elasticache.sp @@ -10,6 +10,7 @@ control "elasticache_redis_cluster_automatic_backup_retention_15_days" { query = query.elasticache_redis_cluster_automatic_backup_retention_15_days tags = merge(local.conformance_pack_elasticache_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" diff --git a/conformance_pack/elb.sp b/conformance_pack/elb.sp index f6ec1045..6b4be60a 100644 --- a/conformance_pack/elb.sp +++ b/conformance_pack/elb.sp @@ -10,6 +10,7 @@ control "elb_application_classic_lb_logging_enabled" { query = query.elb_application_classic_lb_logging_enabled tags = merge(local.conformance_pack_elb_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -194,6 +195,26 @@ control "elb_application_classic_network_lb_prohibit_public_access" { }) } +control "elb_application_lb_listener_certificate_expire_7_days" { + title = "ELB application load balancers secured listener certificate should not expire within next 7 days" + description = "This control ensures that SSL/TLS certificates used in application load balancers are renewed 7 days before their expiration date." + query = query.elb_application_lb_listener_certificate_expire_7_days + + tags = merge(local.conformance_pack_elb_common_tags, { + other_checks = "true" + }) +} + +control "elb_application_lb_listener_certificate_expire_30_days" { + title = "ELB application load balancers secured listener certificate should not expire within next 30 days" + description = "This control ensures that SSL/TLS certificates used in application load balancers are renewed 30 days before their expiration date." + query = query.elb_application_lb_listener_certificate_expire_30_days + + tags = merge(local.conformance_pack_elb_common_tags, { + other_checks = "true" + }) +} + control "elb_application_lb_with_outbound_rule" { title = "ELB application load balancers should have at least one outbound rule" description = "Ensure application load balancers have at least one outbound rule in all the attached security groups. A security group without any outbound rule rejects all outgoing traffic. This means that all outgoing traffic originating from your cloud assets (instances, containers, etc.) will be dropped when it reaches the ELB layer." @@ -204,6 +225,16 @@ control "elb_application_lb_with_outbound_rule" { }) } +control "elb_application_network_lb_use_listeners" { + title = "ELB application and network load balancers should use listeners" + description = "Ensure that application and network load balancer must have one or more listeners. A listener is a process that checks for connection requests, using the protocol and port that you configure. The rules that you define for a listener determine how the load balancer routes requests to its registered targets." + query = query.elb_application_network_lb_use_listeners + + tags = merge(local.conformance_pack_elb_common_tags, { + other_checks = "true" + }) +} + control "elb_classic_lb_with_outbound_rule" { title = "ELB classic load balancers should have at least one outbound rule" description = "Ensure classic load balancers have at least one outbound rule in all the attached security groups. A security group without any outbound rule rejects all outgoing traffic. This means that all outgoing traffic originating from your cloud assets (instances, containers, etc.) will be dropped when it reaches the ELB layer." @@ -214,3 +245,12 @@ control "elb_classic_lb_with_outbound_rule" { }) } +control "elb_tls_listener_protocol_version" { + title = "ELB listeners SSL/TLS protocol version should be checked" + description = "Using insecure ciphers for your ELB Predefined or Custom Security Policy, could make the SSL connection between the client and the load balancer vulnerable to exploits. TLS 1.0 was recommended to be disabled by PCI Council after June 30, 2016." + query = query.elb_tls_listener_protocol_version + + tags = merge(local.conformance_pack_elb_common_tags, { + other_checks = "true" + }) +} \ No newline at end of file diff --git a/conformance_pack/emr.sp b/conformance_pack/emr.sp index d8d79ee9..628348e8 100644 --- a/conformance_pack/emr.sp +++ b/conformance_pack/emr.sp @@ -4,18 +4,29 @@ locals { }) } +control "emr_account_public_access_blocked" { + title = "EMR public access should be blocked at account level" + description = "The block public access feature prevents a cluster in a public subnet from launching when any security group associated with the cluster has a rule that allows inbound traffic from IPv4 0.0.0.0/0 or IPv6 ::/0 (public access) on a port, unless the port has been specified as an exception - port 22 is an exception by default. This feature is enabled by default for each AWS Region in your AWS account and is not recommended to be turned off." + query = query.emr_account_public_access_blocked + + tags = merge(local.conformance_pack_emr_common_tags, { + other_checks = "true" + }) +} + control "emr_cluster_kerberos_enabled" { title = "EMR cluster Kerberos should be enabled" description = "The access permissions and authorizations can be managed and incorporated with the principles of least privilege and separation of duties, by enabling Kerberos for Amazon EMR clusters." query = query.emr_cluster_kerberos_enabled tags = merge(local.conformance_pack_emr_common_tags, { - ffiec = "true" - gxp_21_cfr_part_11 = "true" - hipaa = "true" - nist_800_171_rev_2 = "true" - nist_800_53_rev_4 = "true" - nist_csf = "true" + cis_controls_v8_ig1 = "true" + ffiec = "true" + gxp_21_cfr_part_11 = "true" + hipaa = "true" + nist_800_171_rev_2 = "true" + nist_800_53_rev_4 = "true" + nist_csf = "true" }) } @@ -25,6 +36,7 @@ control "emr_cluster_master_nodes_no_public_ip" { query = query.emr_cluster_master_nodes_no_public_ip tags = merge(local.conformance_pack_emr_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" diff --git a/conformance_pack/es.sp b/conformance_pack/es.sp index c55e0e52..38853982 100644 --- a/conformance_pack/es.sp +++ b/conformance_pack/es.sp @@ -31,6 +31,7 @@ control "es_domain_in_vpc" { query = query.es_domain_in_vpc tags = merge(local.conformance_pack_es_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -71,6 +72,7 @@ control "es_domain_logs_to_cloudwatch" { query = query.es_domain_logs_to_cloudwatch tags = merge(local.conformance_pack_es_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" diff --git a/conformance_pack/guardduty.sp b/conformance_pack/guardduty.sp index 65858e32..aeeab690 100644 --- a/conformance_pack/guardduty.sp +++ b/conformance_pack/guardduty.sp @@ -10,6 +10,7 @@ control "guardduty_enabled" { query = query.guardduty_enabled tags = merge(local.conformance_pack_guardduty_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" diff --git a/conformance_pack/iam.sp b/conformance_pack/iam.sp index e102730d..ad23fefc 100644 --- a/conformance_pack/iam.sp +++ b/conformance_pack/iam.sp @@ -22,6 +22,7 @@ control "iam_group_not_empty" { query = query.iam_group_not_empty tags = merge(local.conformance_pack_iam_common_tags, { + cis_controls_v8_ig1 = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" ffiec = "true" @@ -40,6 +41,7 @@ control "iam_policy_no_star_star" { query = query.iam_policy_custom_no_star_star tags = merge(local.conformance_pack_iam_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -62,6 +64,7 @@ control "iam_root_user_no_access_keys" { query = query.iam_root_user_no_access_keys tags = merge(local.conformance_pack_iam_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -83,6 +86,7 @@ control "iam_root_user_hardware_mfa_enabled" { query = query.iam_root_user_hardware_mfa_enabled tags = merge(local.conformance_pack_iam_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -104,6 +108,7 @@ control "iam_root_user_mfa_enabled" { tags = merge(local.conformance_pack_iam_common_tags, { audit_manager_control_tower = "true" + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -144,6 +149,7 @@ control "iam_user_console_access_mfa_enabled" { tags = merge(local.conformance_pack_iam_common_tags, { audit_manager_control_tower = "true" + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -184,6 +190,7 @@ control "iam_user_no_inline_attached_policies" { query = query.iam_user_no_inline_attached_policies tags = merge(local.conformance_pack_iam_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -227,6 +234,7 @@ control "iam_user_in_group" { query = query.iam_user_in_group tags = merge(local.conformance_pack_iam_common_tags, { + cis_controls_v8_ig1 = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" ffiec = "true" @@ -246,6 +254,7 @@ control "iam_group_user_role_no_inline_policies" { query = query.iam_group_user_role_no_inline_policies tags = merge(local.conformance_pack_iam_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -276,6 +285,7 @@ control "iam_account_password_policy_min_length_14" { query = query.iam_account_password_policy_min_length_14 tags = merge(local.conformance_pack_iam_common_tags, { + cis_controls_v8_ig1 = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" gdpr = "true" @@ -376,6 +386,7 @@ control "iam_all_policy_no_service_wild_card" { query = query.iam_policy_custom_no_service_wildcard tags = merge(local.conformance_pack_iam_common_tags, { + cis_controls_v8_ig1 = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" ffiec = "true" @@ -416,8 +427,9 @@ control "account_part_of_organizations" { query = query.account_part_of_organizations tags = merge(local.conformance_pack_iam_common_tags, { - gxp_21_cfr_part_11 = "true" - nist_800_53_rev_5 = "true" + cis_controls_v8_ig1 = "true" + gxp_21_cfr_part_11 = "true" + nist_800_53_rev_5 = "true" }) } @@ -480,3 +492,23 @@ control "iam_user_with_administrator_access_mfa_enabled" { other_checks = "true" }) } + +control "iam_managed_policy_attached_to_role" { + title = "IAM AWS managed policies should be attached to IAM role" + description = "This control checks if all AWS managed policies specified in the list of managed policies are attached to the AWS Identity and Access Management (IAM) role. The rule is non compliant if an AWS managed policy is not attached to the IAM role." + query = query.iam_managed_policy_attached_to_role + + tags = merge(local.conformance_pack_iam_common_tags, { + cis_controls_v8_ig1 = "true" + }) +} + +control "iam_policy_unused" { + title = "IAM policy should be in use" + description = "This control checks whether the IAM policy ARN is attached to an IAM user, or a group with one or more IAM users, or an IAM role with one or more trusted entity." + query = query.iam_policy_unused + + tags = merge(local.conformance_pack_iam_common_tags, { + cis_controls_v8_ig1 = "true" + }) +} diff --git a/conformance_pack/kms.sp b/conformance_pack/kms.sp index 095ccfd2..80dfaf03 100644 --- a/conformance_pack/kms.sp +++ b/conformance_pack/kms.sp @@ -28,6 +28,7 @@ control "kms_cmk_rotation_enabled" { query = query.kms_cmk_rotation_enabled tags = merge(local.conformance_pack_kms_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" diff --git a/conformance_pack/lambda.sp b/conformance_pack/lambda.sp index 86cc1ac5..49294909 100644 --- a/conformance_pack/lambda.sp +++ b/conformance_pack/lambda.sp @@ -27,6 +27,7 @@ control "lambda_function_in_vpc" { query = query.lambda_function_in_vpc tags = merge(local.conformance_pack_lambda_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -47,6 +48,7 @@ control "lambda_function_restrict_public_access" { query = query.lambda_function_restrict_public_access tags = merge(local.conformance_pack_lambda_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -85,3 +87,13 @@ control "lambda_function_cloudtrail_logging_enabled" { other_checks = "true" }) } + +control "lambda_function_tracing_enabled" { + title = "Lambda functions tracing should be enabled" + description = "AWS X-Ray can be used to visualize the components of application, identify performance bottlenecks, and troubleshoot requests that resulted in an error. Lambda functions send trace data to X-Ray, and X-Ray processes the data to generate a service map and searchable trace summaries." + query = query.lambda_function_tracing_enabled + + tags = merge(local.conformance_pack_lambda_common_tags, { + other_checks = "true" + }) +} diff --git a/conformance_pack/rds.sp b/conformance_pack/rds.sp index 482ab53a..634aedcc 100644 --- a/conformance_pack/rds.sp +++ b/conformance_pack/rds.sp @@ -10,6 +10,7 @@ control "rds_db_instance_backup_enabled" { query = query.rds_db_instance_backup_enabled tags = merge(local.conformance_pack_rds_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -32,6 +33,7 @@ control "rds_db_instance_encryption_at_rest_enabled" { query = query.rds_db_instance_encryption_at_rest_enabled tags = merge(local.conformance_pack_rds_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_moderate_rev_4 = "true" ffiec = "true" @@ -72,6 +74,7 @@ control "rds_db_instance_prohibit_public_access" { tags = merge(local.conformance_pack_rds_common_tags, { audit_manager_control_tower = "true" + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -114,6 +117,7 @@ control "rds_db_snapshot_prohibit_public_access" { tags = merge(local.conformance_pack_rds_common_tags, { audit_manager_control_tower = "true" + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -134,6 +138,7 @@ control "rds_db_instance_logging_enabled" { query = query.rds_db_instance_logging_enabled tags = merge(local.conformance_pack_rds_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -154,6 +159,7 @@ control "rds_db_instance_in_backup_plan" { query = query.rds_db_instance_in_backup_plan tags = merge(local.conformance_pack_rds_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" ffiec = "true" gdpr = "true" @@ -215,7 +221,7 @@ control "rds_db_instance_iam_authentication_enabled" { control "rds_db_cluster_iam_authentication_enabled" { title = "IAM authentication should be configured for RDS clusters" - description = "Checks if an Amazon RDS Cluster has AWS Identity and Access Management (IAM) authentication enabled. The rule is NON_COMPLIANT if an RDS Cluster does not have IAM authentication enabled." + description = "Checks if an Amazon RDS Cluster has AWS Identity and Access Management (IAM) authentication enabled. The rule is non compliant if an RDS Cluster does not have IAM authentication enabled." query = query.rds_db_cluster_iam_authentication_enabled tags = merge(local.conformance_pack_rds_common_tags, { @@ -260,7 +266,7 @@ control "rds_db_instance_protected_by_backup_plan" { control "rds_db_instance_automatic_minor_version_upgrade_enabled" { title = "RDS DB instance automatic minor version upgrade should be enabled" - description = "Ensure if Amazon Relational Database Service (RDS) database instances are configured for automatic minor version upgrades. The rule is NON_COMPLIANT if the value of 'autoMinorVersionUpgrade' is false." + description = "Ensure if Amazon Relational Database Service (RDS) database instances are configured for automatic minor version upgrades. The rule is non compliant if the value of 'autoMinorVersionUpgrade' is false." query = query.rds_db_instance_automatic_minor_version_upgrade_enabled tags = merge(local.conformance_pack_rds_common_tags, { diff --git a/conformance_pack/redshift.sp b/conformance_pack/redshift.sp index 455c47c0..67a5bd45 100644 --- a/conformance_pack/redshift.sp +++ b/conformance_pack/redshift.sp @@ -31,6 +31,7 @@ control "redshift_cluster_encryption_logging_enabled" { query = query.redshift_cluster_encryption_logging_enabled tags = merge(local.conformance_pack_redshift_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -53,6 +54,7 @@ control "redshift_cluster_prohibit_public_access" { query = query.redshift_cluster_prohibit_public_access tags = merge(local.conformance_pack_redshift_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -73,6 +75,7 @@ control "redshift_cluster_automatic_snapshots_min_7_days" { query = query.redshift_cluster_automatic_snapshots_min_7_days tags = merge(local.conformance_pack_redshift_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -111,6 +114,7 @@ control "redshift_cluster_maintenance_settings_check" { query = query.redshift_cluster_maintenance_settings_check tags = merge(local.conformance_pack_redshift_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" ffiec = "true" nist_800_53_rev_5 = "true" diff --git a/conformance_pack/route53.sp b/conformance_pack/route53.sp index 2356194f..c54fcaa6 100644 --- a/conformance_pack/route53.sp +++ b/conformance_pack/route53.sp @@ -4,6 +4,16 @@ locals { }) } +control "route53_domain_auto_renew_enabled" { + title = "Route 53 domains auto renew should be enabled" + description = "This control ensures that AWS Route 53 Auto Renew feature is enabled to automatically renew your domain names as the expiration date approaches." + query = query.route53_domain_auto_renew_enabled + + tags = merge(local.conformance_pack_route53_common_tags, { + other_checks = "true" + }) +} + control "route53_zone_query_logging_enabled" { title = "Route 53 zones should have query logging enabled" description = "Ensure Route 53 zones have query logging enabled." @@ -14,6 +24,46 @@ control "route53_zone_query_logging_enabled" { }) } +control "route53_domain_expires_30_days" { + title = "Route 53 domains should not expire within next 30 days" + description = "This control ensures that all the domain names registered with AWS Route 53 or transferred to AWS Route 53 are renewed 30 days before their validity period ends." + query = query.route53_domain_expires_30_days + + tags = merge(local.conformance_pack_route53_common_tags, { + other_checks = "true" + }) +} + +control "route53_domain_expires_7_days" { + title = "Route 53 domains should not expire within next 7 days" + description = "This controls ensures that all the domain names registered with AWS Route 53 or transferred to AWS Route 53 are renewed 7 days before their validity period ends." + query = query.route53_domain_expires_7_days + + tags = merge(local.conformance_pack_route53_common_tags, { + other_checks = "true" + }) +} + +control "route53_domain_not_expired" { + title = "Route 53 domains should not be expired" + description = "This control identifes any expired domain names registered with AWS Route 53. When the expired domain names are not restored promptly, they will become available for others to register. Restoring on time your Route 53 expired domains will allow you to reestablish full control over their registration." + query = query.route53_domain_not_expired + + tags = merge(local.conformance_pack_route53_common_tags, { + other_checks = "true" + }) +} + +control "route53_domain_privacy_protection_enabled" { + title = "Route53 domains privacy protection should be enabled" + description = "Ensure that your Amazon Route 53 domains have Privacy Protection feature enabled in order to hide all their contact information from WHOIS queries and reduce the amount of spam received. The feature allows you to conceal your personal phone number, email and physical address for the domain names registered and/or transferred to AWS Route 53 service." + query = query.route53_domain_privacy_protection_enabled + + tags = merge(local.conformance_pack_route53_common_tags, { + other_checks = "true" + }) +} + control "route53_domain_transfer_lock_enabled" { title = "Route 53 domains should have transfer lock enabled" description = "Ensure Route 53 registered domains are locked to prevent any unauthorized transfers to another domain name registrar." diff --git a/conformance_pack/s3.sp b/conformance_pack/s3.sp index e544b0e0..46ae2921 100644 --- a/conformance_pack/s3.sp +++ b/conformance_pack/s3.sp @@ -10,6 +10,7 @@ control "s3_bucket_cross_region_replication_enabled" { query = query.s3_bucket_cross_region_replication_enabled tags = merge(local.conformance_pack_s3_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -31,6 +32,7 @@ control "s3_bucket_default_encryption_enabled" { query = query.s3_bucket_default_encryption_enabled tags = merge(local.conformance_pack_s3_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -52,6 +54,7 @@ control "s3_bucket_enforces_ssl" { query = query.s3_bucket_enforces_ssl tags = merge(local.conformance_pack_s3_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -73,6 +76,7 @@ control "s3_bucket_logging_enabled" { query = query.s3_bucket_logging_enabled tags = merge(local.conformance_pack_s3_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -111,6 +115,7 @@ control "s3_bucket_restrict_public_read_access" { tags = merge(local.conformance_pack_s3_common_tags, { audit_manager_control_tower = "true" + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -133,6 +138,7 @@ control "s3_bucket_restrict_public_write_access" { tags = merge(local.conformance_pack_s3_common_tags, { audit_manager_control_tower = "true" + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -154,6 +160,7 @@ control "s3_bucket_versioning_enabled" { tags = merge(local.conformance_pack_s3_common_tags, { audit_manager_control_tower = "true" + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -170,12 +177,23 @@ control "s3_bucket_versioning_enabled" { }) } +control "s3_bucket_static_website_hosting_disabled" { + title = "S3 buckets static website hosting should be disabled" + description = "Enabling static website on a S3 bucket requires to grant public read access to the bucket. There is a potential risk of exposure when you turn off block public access settings to make your bucket public. This is recommend to not configure static website on S3 bucket." + query = query.s3_bucket_static_website_hosting_disabled + + tags = merge(local.conformance_pack_s3_common_tags, { + other_checks = "true" + }) +} + control "s3_public_access_block_account" { title = "S3 public access should be blocked at account level" description = "Manage access to resources in the AWS Cloud by ensuring that Amazon Simple Storage Service (Amazon S3) buckets cannot be publicly accessed." query = query.s3_public_access_block_account tags = merge(local.conformance_pack_s3_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -232,6 +250,7 @@ control "s3_public_access_block_bucket" { query = query.s3_public_access_block_bucket tags = merge(local.conformance_pack_s3_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -247,7 +266,8 @@ control "s3_bucket_policy_restricts_cross_account_permission_changes" { query = query.s3_bucket_policy_restricts_cross_account_permission_changes tags = merge(local.conformance_pack_s3_common_tags, { - nist_800_171_rev_2 = "true" + cis_controls_v8_ig1 = "true" + nist_800_171_rev_2 = "true" }) } diff --git a/conformance_pack/sagemaker.sp b/conformance_pack/sagemaker.sp index 258dbc61..d39fadf2 100644 --- a/conformance_pack/sagemaker.sp +++ b/conformance_pack/sagemaker.sp @@ -4,12 +4,23 @@ locals { }) } +control "sagemaker_notebook_instance_encrypted_with_kms_cmk" { + title = "SageMaker notebook instances should be encrypted using CMK" + description = "This control checks if SageMaker notebook instance storage volumes are encrypted with Amazon KMS Customer Master Keys (CMKs) instead of AWS managed-keys." + query = query.sagemaker_notebook_instance_encrypted_with_kms_cmk + + tags = merge(local.conformance_pack_sagemaker_common_tags, { + other_checks = "true" + }) +} + control "sagemaker_notebook_instance_direct_internet_access_disabled" { title = "SageMaker notebook instances should not have direct internet access" description = "Manage access to resources in the AWS Cloud by ensuring that Amazon SageMaker notebooks do not allow direct internet access." query = query.sagemaker_notebook_instance_direct_internet_access_disabled tags = merge(local.conformance_pack_sagemaker_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" diff --git a/conformance_pack/secretsmanager.sp b/conformance_pack/secretsmanager.sp index 6bd6f06a..a3ad149b 100644 --- a/conformance_pack/secretsmanager.sp +++ b/conformance_pack/secretsmanager.sp @@ -44,7 +44,7 @@ control "secretsmanager_secret_unused_90_day" { control "secretsmanager_secret_encrypted_with_kms_cmk" { title = "Secrets Manager secrets should be encrypted using CMK" - description = "Ensure if all secrets in AWS Secrets Manager are encrypted using the AWS managed key (aws/secretsmanager) or a customer managed key that was created in AWS Key Management Service (AWS KMS). The rule is compliant if a secret is encrypted using a customer managed key. This rule is NON_COMPLIANT if a secret is encrypted using aws/secretsmanager." + description = "Ensure if all secrets in AWS Secrets Manager are encrypted using the AWS managed key (aws/secretsmanager) or a customer managed key that was created in AWS Key Management Service (AWS KMS). The rule is compliant if a secret is encrypted using a customer managed key. This rule is non compliant if a secret is encrypted using aws/secretsmanager." query = query.secretsmanager_secret_encrypted_with_kms_cmk tags = merge(local.conformance_pack_secretsmanager_common_tags, { diff --git a/conformance_pack/ssm.sp b/conformance_pack/ssm.sp index fec03853..c43162ae 100644 --- a/conformance_pack/ssm.sp +++ b/conformance_pack/ssm.sp @@ -10,6 +10,7 @@ control "ec2_instance_ssm_managed" { query = query.ec2_instance_ssm_managed tags = merge(local.conformance_pack_ssm_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -31,6 +32,7 @@ control "ssm_managed_instance_compliance_association_compliant" { query = query.ssm_managed_instance_compliance_association_compliant tags = merge(local.conformance_pack_ssm_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -52,6 +54,7 @@ control "ssm_managed_instance_compliance_patch_compliant" { query = query.ssm_managed_instance_compliance_patch_compliant tags = merge(local.conformance_pack_ssm_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" diff --git a/conformance_pack/vpc.sp b/conformance_pack/vpc.sp index a304ddeb..5cb45c3c 100644 --- a/conformance_pack/vpc.sp +++ b/conformance_pack/vpc.sp @@ -10,6 +10,7 @@ control "vpc_flow_logs_enabled" { query = query.vpc_flow_logs_enabled tags = merge(local.conformance_pack_vpc_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -89,6 +90,7 @@ control "vpc_security_group_restrict_ingress_ssh_all" { tags = merge(local.conformance_pack_vpc_common_tags, { audit_manager_control_tower = "true" + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -110,6 +112,7 @@ control "vpc_default_security_group_restricts_all_traffic" { query = query.vpc_default_security_group_restricts_all_traffic tags = merge(local.conformance_pack_vpc_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -145,6 +148,7 @@ control "vpc_eip_associated" { query = query.vpc_eip_associated tags = merge(local.conformance_pack_vpc_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" ffiec = "true" nist_800_171_rev_2 = "true" @@ -158,8 +162,9 @@ control "vpc_security_group_associated_to_eni" { query = query.vpc_security_group_associated_to_eni tags = merge(local.conformance_pack_vpc_common_tags, { - nist_800_171_rev_2 = "true" - nist_csf = "true" + cis_controls_v8_ig1 = "true" + nist_800_171_rev_2 = "true" + nist_csf = "true" }) } @@ -169,6 +174,7 @@ control "vpc_subnet_auto_assign_public_ip_disabled" { query = query.vpc_subnet_auto_assign_public_ip_disabled tags = merge(local.conformance_pack_vpc_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" @@ -218,10 +224,20 @@ control "vpc_security_group_restrict_ingress_redis_port" { }) } -control "vpc_security_group_restrict_kibana_port" { +control "vpc_security_group_restrict_ingress_kafka_port" { + title = "VPC security groups should restrict ingress Kafka port access from 0.0.0.0/0" + description = "Amazon VPC security groups can help in managing network access by providing stateful filtering of ingress and egress network traffic to AWS resources." + query = query.vpc_security_group_restrict_ingress_kafka_port + + tags = merge(local.conformance_pack_vpc_common_tags, { + other_checks = "true" + }) +} + +control "vpc_security_group_restrict_ingress_kibana_port" { title = "VPC security groups should restrict ingress kibana port access from 0.0.0.0/0" description = "Amazon VPC security groups can help in managing network access by providing stateful filtering of ingress and egress network traffic to AWS resources." - query = query.vpc_security_group_restrict_kibana_port + query = query.vpc_security_group_restrict_ingress_kibana_port tags = merge(local.conformance_pack_vpc_common_tags, { other_checks = "true" @@ -254,6 +270,7 @@ control "vpc_network_acl_unused" { query = query.vpc_network_acl_unused tags = merge(local.conformance_pack_vpc_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" }) } diff --git a/conformance_pack/wafv2.sp b/conformance_pack/wafv2.sp index a8786559..f16f409c 100644 --- a/conformance_pack/wafv2.sp +++ b/conformance_pack/wafv2.sp @@ -10,6 +10,7 @@ control "wafv2_web_acl_logging_enabled" { query = query.wafv2_web_acl_logging_enabled tags = merge(local.conformance_pack_wafv2_common_tags, { + cis_controls_v8_ig1 = "true" cisa_cyber_essentials = "true" fedramp_low_rev_4 = "true" fedramp_moderate_rev_4 = "true" diff --git a/foundational_security/docs/foundational_security_ecr_2.md b/foundational_security/docs/foundational_security_ecr_2.md index 18f25e15..25498285 100644 --- a/foundational_security/docs/foundational_security_ecr_2.md +++ b/foundational_security/docs/foundational_security_ecr_2.md @@ -6,4 +6,4 @@ Amazon ECR Tag Immutability enables customers to rely on the descriptive tags of ## Remediation -To configure image scanning for an ECR repository, see [Image scanning](https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning.html) in the Amazon Elastic Container Registry User Guide. \ No newline at end of file +To create a repository with immutable tags configured or to update the image tag mutability settings for an existing repository, see [Image tag mutability](https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-tag-mutability.html) in the Amazon Elastic Container Registry User Guide. \ No newline at end of file diff --git a/mod.sp b/mod.sp index d7aa87f4..1fffd503 100644 --- a/mod.sp +++ b/mod.sp @@ -24,7 +24,7 @@ mod "aws_compliance" { require { plugin "aws" { - version = "0.92.0" + version = "0.95.0" } } } diff --git a/other_checks/other.sp b/other_checks/other.sp index f6994795..c5f36014 100644 --- a/other_checks/other.sp +++ b/other_checks/other.sp @@ -15,22 +15,38 @@ benchmark "other" { control.cloudformation_stack_notifications_enabled, control.cloudformation_stack_output_no_secrets, control.cloudformation_stack_rollback_enabled, + control.cloudformation_stack_termination_protection_enabled, control.cloudfront_distribution_geo_restrictions_enabled, + control.cloudfront_distribution_non_s3_origins_encryption_in_transit_enabled, + control.cloudfront_distribution_use_secure_cipher, + control.cloudwatch_cross_account_sharing, + control.codebuild_project_build_greater_then_90_days, + control.codebuild_project_with_user_controlled_buildspec, + control.ec2_instance_no_high_level_finding_in_inspector_scan, control.ec2_instance_no_launch_wizard_security_group, control.ec2_instance_publicly_accessible_iam_profile_attached, control.ec2_instance_user_data_no_secrets, control.ec2_transit_gateway_auto_cross_account_attachment_disabled, control.ecr_repository_image_scan_on_push_enabled, control.ecr_repository_prohibit_public_access, + control.ecs_cluster_encryption_at_rest_enabled, + control.ecs_cluster_instance_in_vpc, + control.ecs_cluster_no_registered_container_instance, + control.ecs_service_load_balancer_attached, control.ecs_task_definition_logging_enabled, control.efs_file_system_encrypted_with_cmk, control.efs_file_system_enforces_ssl, control.eks_cluster_control_plane_audit_logging_enabled, control.eks_cluster_no_default_vpc, control.elb_application_classic_network_lb_prohibit_public_access, + control.elb_application_lb_listener_certificate_expire_30_days, + control.elb_application_lb_listener_certificate_expire_7_days, control.elb_application_lb_with_outbound_rule, + control.elb_application_network_lb_use_listeners, control.elb_classic_lb_with_outbound_rule, control.elb_listener_use_secure_ssl_cipher, + control.elb_tls_listener_protocol_version, + control.emr_account_public_access_blocked, control.es_domain_cognito_authentication_enabled, control.es_domain_internal_user_database_enabled, control.glue_dev_endpoint_cloudwatch_logs_encryption_enabled, @@ -46,13 +62,21 @@ benchmark "other" { control.kinesis_stream_server_side_encryption_enabled, control.kms_cmk_policy_prohibit_public_access, control.lambda_function_cloudtrail_logging_enabled, + control.lambda_function_tracing_enabled, control.rds_db_instance_ca_certificate_expires_7_days, control.rds_db_instance_cloudwatch_logs_enabled, + control.route53_domain_auto_renew_enabled, + control.route53_domain_expires_30_days, + control.route53_domain_expires_7_days, + control.route53_domain_not_expired, + control.route53_domain_privacy_protection_enabled, control.route53_domain_transfer_lock_enabled, control.route53_zone_query_logging_enabled, control.s3_bucket_object_logging_enabled, + control.s3_bucket_static_website_hosting_disabled, control.sagemaker_model_in_vpc, control.sagemaker_model_network_isolation_enabled, + control.sagemaker_notebook_instance_encrypted_with_kms_cmk, control.sagemaker_notebook_instance_in_vpc, control.sagemaker_notebook_instance_root_access_disabled, control.sagemaker_training_job_in_vpc, @@ -65,7 +89,8 @@ benchmark "other" { control.vpc_endpoint_service_acceptance_required_enabled, control.vpc_security_group_not_uses_launch_wizard_sg, control.vpc_security_group_restrict_ingress_redis_port, - control.vpc_security_group_restrict_kibana_port + control.vpc_security_group_restrict_ingress_kafka_port, + control.vpc_security_group_restrict_ingress_kibana_port ] tags = merge(local.other_common_tags, { diff --git a/query/cloudformation/cloudformation_stack_termination_protection_enabled.sql b/query/cloudformation/cloudformation_stack_termination_protection_enabled.sql new file mode 100644 index 00000000..94190d5a --- /dev/null +++ b/query/cloudformation/cloudformation_stack_termination_protection_enabled.sql @@ -0,0 +1,16 @@ +select + -- Required Columns + id as resource, + case + when enable_termination_protection then 'ok' + else 'alarm' + end as status, + case + when enable_termination_protection then title || ' termination protection enabled.' + else title || ' termination protection disabled.' + end as reason, + -- Additional Dimensions + region, + account_id +from + aws_cloudformation_stack; diff --git a/query/cloudfront/cloudfront_distribution_non_s3_origins_encryption_in_transit_enabled.sql b/query/cloudfront/cloudfront_distribution_non_s3_origins_encryption_in_transit_enabled.sql new file mode 100644 index 00000000..d8e34753 --- /dev/null +++ b/query/cloudfront/cloudfront_distribution_non_s3_origins_encryption_in_transit_enabled.sql @@ -0,0 +1,45 @@ +with viewer_protocol_policy_value as ( + select + distinct arn + from + aws_cloudfront_distribution, + jsonb_array_elements( + case jsonb_typeof(cache_behaviors -> 'Items') + when 'array' then (cache_behaviors -> 'Items') + else null end + ) as cb + where + cb ->> 'ViewerProtocolPolicy' = 'allow-all' +), +origin_protocol_policy_value as ( + select + distinct arn, + o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' as origin_protocol_policy + from + aws_cloudfront_distribution, + jsonb_array_elements(origins) as o + where + o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' = 'http-only' + or o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' = 'match-viewer' + and o -> 'S3OriginConfig' is null +) +select + -- Required Columns + b.arn as resource, + case + when o.arn is not null and o.origin_protocol_policy = 'http-only' then 'alarm' + when o.arn is not null and o.origin_protocol_policy = 'match-viewer' and ( v.arn is not null or (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') ) then 'alarm' + else 'ok' + end as status, + case + when o.arn is not null and o.origin_protocol_policy = 'http-only' then title || ' origins traffic not encrypted in transit.' + when o.arn is not null and o.origin_protocol_policy = 'match-viewer' and ( v.arn is not null or (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') ) then title || ' origins traffic not encrypted in transit.' + else title || ' origins traffic encrypted in transit.' + end as reason, + -- Additional Dimensions + region, + account_id +from + aws_cloudfront_distribution as b + left join origin_protocol_policy_value as o on b.arn = o.arn + left join viewer_protocol_policy_value as v on b.arn = v.arn; \ No newline at end of file diff --git a/query/cloudfront/cloudfront_distribution_use_secure_cipher.sql b/query/cloudfront/cloudfront_distribution_use_secure_cipher.sql new file mode 100644 index 00000000..35876eab --- /dev/null +++ b/query/cloudfront/cloudfront_distribution_use_secure_cipher.sql @@ -0,0 +1,27 @@ +with origin_protocols as ( + select + distinct arn, + o -> 'CustomOriginConfig' ->> 'OriginSslProtocols' as origin_ssl_policy + from + aws_cloudfront_distribution, + jsonb_array_elements(origins) as o + where + o -> 'CustomOriginConfig' -> 'OriginSslProtocols' -> 'Items' @> '["TLSv1.2%", "TLSv1.1%"]' +) +select + -- Required Columns + b.arn as resource, + case + when o.arn is not null then 'ok' + else 'alarm' + end as status, + case + when o.arn is not null then title || ' use secure cipher.' + else title || ' does not use secure cipher.' + end as reason, + -- Additional Dimensions + region, + account_id +from + aws_cloudfront_distribution as b + left join origin_protocols as o on b.arn = o.arn; \ No newline at end of file diff --git a/query/cloudtrail/cloudtrail_multi_region_trail_enabled.sql b/query/cloudtrail/cloudtrail_multi_region_trail_enabled.sql index 37b91a6b..0269efcc 100644 --- a/query/cloudtrail/cloudtrail_multi_region_trail_enabled.sql +++ b/query/cloudtrail/cloudtrail_multi_region_trail_enabled.sql @@ -10,17 +10,35 @@ with multi_region_trails as ( group by account_id, is_multi_region_trail +), organization_trails as ( + select + is_organization_trail, + is_logging, + is_multi_region_trail, + account_id + from + aws_cloudtrail_trail + where + is_organization_trail ) select -- Required Columns - a.arn as resource, + distinct a.arn as resource, case - when coalesce(num_multregion_trails, 0) < 1 then 'alarm' - else 'ok' + when coalesce(num_multregion_trails, 0) >= 1 then 'ok' + when o.is_organization_trail and o.is_logging and o.is_multi_region_trail then 'ok' + when o.is_organization_trail and o.is_multi_region_trail and o.is_logging is null then 'info' + else 'alarm' end as status, - a.title || ' has ' || coalesce(num_multregion_trails, 0) || ' multi-region trail(s).' as reason, + case + when coalesce(num_multregion_trails, 0) >= 1 then a.title || ' has ' || coalesce(num_multregion_trails, 0) || ' multi-region trail(s).' + when o.is_organization_trail and o.is_logging and o.is_multi_region_trail then a.title || ' has multi-region trail(s).' + when o.is_organization_trail and o.is_multi_region_trail and o.is_logging is null then a.title || ' has organization trail, check organization account for cloudtrail logging status.' + else a.title || ' does not have multi-region trail(s).' + end as reason, -- Additional Dimensions a.account_id from aws_account as a -left join multi_region_trails as b on a.account_id = b.account_id; \ No newline at end of file + left join multi_region_trails as b on a.account_id = b.account_id + left join organization_trails as o on a.account_id = o.account_id \ No newline at end of file diff --git a/query/cloudwatch/cloudwatch_cross_account_sharing.sql b/query/cloudwatch/cloudwatch_cross_account_sharing.sql new file mode 100644 index 00000000..76c1120e --- /dev/null +++ b/query/cloudwatch/cloudwatch_cross_account_sharing.sql @@ -0,0 +1,27 @@ +with iam_role_cross_account_sharing_count as ( + select + arn, + replace(replace(replace((a -> 'Principal' ->> 'AWS'), '[',''), ']', ''), '"', '') as cross_account_details, + account_id + from + aws_iam_role, + jsonb_array_elements(assume_role_policy_std -> 'Statement') as a + where + name = 'CloudWatch-CrossAccountSharingRole' +) +select + -- Required Columns + a.arn as resource, + case + when c.arn is null then 'ok' + else 'info' + end as status, + case + when c.arn is null then 'CloudWatch does not allow cross-account sharing.' + else 'CloudWatch allow cross-account sharing with '|| cross_account_details || '.' + end as reason, + -- Additional Dimensions + a.account_id +from + aws_account as a + left join iam_role_cross_account_sharing_count as c on c.account_id = a.account_id; \ No newline at end of file diff --git a/query/codebuild/codebuild_project_artifact_encryption_enabled.sql b/query/codebuild/codebuild_project_artifact_encryption_enabled.sql new file mode 100644 index 00000000..fd3cfc5b --- /dev/null +++ b/query/codebuild/codebuild_project_artifact_encryption_enabled.sql @@ -0,0 +1,28 @@ +with secondary_artifact as ( + select + distinct arn + from + aws_codebuild_project, + jsonb_array_elements(secondary_artifacts) as a + where + a -> 'EncryptionDisabled' = 'true' +) +select + -- Required Columns + a.arn as resource, + case + when p.artifacts ->> 'EncryptionDisabled' = 'false' + and (p.secondary_artifacts is null or a.arn is null) then 'ok' + else 'alarm' + end as status, + case + when p.artifacts ->> 'EncryptionDisabled' = 'false' + and (p.secondary_artifacts is null or a.arn is null) then p.title || ' all artifacts encryption enabled.' + else p.title || ' all artifacts encryption not enabled.' + end as reason, + -- Additional Dimensions + p.region, + p.account_id +from + aws_codebuild_project as p + left join secondary_artifact as a on a.arn = p.arn; diff --git a/query/codebuild/codebuild_project_build_greater_then_90_days.sql b/query/codebuild/codebuild_project_build_greater_then_90_days.sql new file mode 100644 index 00000000..ea4223ef --- /dev/null +++ b/query/codebuild/codebuild_project_build_greater_then_90_days.sql @@ -0,0 +1,31 @@ +with latest_codebuild_build as ( + select + project_name, + region, + account_id, + min(date_part('day', now() - end_time)) as build_time + from + aws_codebuild_build + group by + project_name, + region, + account_id +) +select + -- Required Columns + p.arn as resource, + case + when b.build_time is null then 'alarm' + when b.build_time < 90 then 'ok' + else 'alarm' + end as status, + case + when b.build_time is null then p.title || ' was never build.' + else p.title || ' was build ' || build_time || ' day(s) before.' + end as reason, + -- Additional Dimensions + p.account_id, + p.region +from + aws_codebuild_project as p + left join latest_codebuild_build as b on p.name = b.project_name and p.region = b.region and p.account_id = b.account_id; \ No newline at end of file diff --git a/query/codebuild/codebuild_project_with_user_controlled_buildspec.sql b/query/codebuild/codebuild_project_with_user_controlled_buildspec.sql new file mode 100644 index 00000000..d3465104 --- /dev/null +++ b/query/codebuild/codebuild_project_with_user_controlled_buildspec.sql @@ -0,0 +1,16 @@ +select + -- Required Columns + arn as resource, + case + when split_part(source ->> 'Buildspec', '.', -1) = 'yml' then 'alarm' + else 'ok' + end as status, + case + when split_part(source ->> 'Buildspec', '.', -1) = 'yml' then title || ' uses a user controlled buildspec.' + else title || ' does not uses a user controlled buildspec.' + end as reason, + -- Additional Dimensions + region, + account_id +from + aws_codebuild_project; \ No newline at end of file diff --git a/query/ec2/ec2_instance_no_high_level_finding_in_inspector_scan.sql b/query/ec2/ec2_instance_no_high_level_finding_in_inspector_scan.sql new file mode 100644 index 00000000..de9d1028 --- /dev/null +++ b/query/ec2/ec2_instance_no_high_level_finding_in_inspector_scan.sql @@ -0,0 +1,37 @@ +with severity_list as ( + select + distinct title , + a ->> 'Value' as instance_id + from + aws_inspector_finding, + jsonb_array_elements(attributes) as a + where + severity = 'High' + and asset_type = 'ec2-instance' + and a ->> 'Key' = 'INSTANCE_ID' + group by + a ->> 'Value', + title +), ec2_istance_list as ( + select + distinct instance_id + from + severity_list +) +select + -- Required Columns + arn as resource, + case + when l.instance_id is null then 'ok' + else 'alarm' + end as status, + case + when l.instance_id is null then i.title || ' has no high level finding in inspector scans.' + else i.title || ' has ' || (select count(*) from severity_list where instance_id = i.instance_id) || ' high level findings in inspector scans.' + end as reason, + -- Additional Dimensions + region, + account_id +from + aws_ec2_instance as i + left join ec2_istance_list as l on i.instance_id = l.instance_id; \ No newline at end of file diff --git a/query/ecs/ecs_cluster_container_instance_agent_connected.sql b/query/ecs/ecs_cluster_container_instance_agent_connected.sql new file mode 100644 index 00000000..90ab359e --- /dev/null +++ b/query/ecs/ecs_cluster_container_instance_agent_connected.sql @@ -0,0 +1,27 @@ +with unconnected_agent_instance as ( + select + distinct cluster_arn + from + aws_ecs_container_instance + where + agent_connected = false and status = 'ACTIVE' +) +select + -- Required Columns + c.cluster_arn as resource, + case + when c.registered_container_instances_count = 0 then 'skip' + when i.cluster_arn is null then 'ok' + else 'alarm' + end as status, + case + when c.registered_container_instances_count = 0 then title || ' has no container instance registered.' + when i.cluster_arn is null then title || ' container instance has connected agent.' + else title || ' container instance is either draining or has unconnected agents.' + end as reason, + -- Additional Dimensions + region, + account_id +from + aws_ecs_cluster as c + left join unconnected_agent_instance as i on c.cluster_arn = i.cluster_arn; \ No newline at end of file diff --git a/query/ecs/ecs_cluster_encryption_at_rest_enabled.sql b/query/ecs/ecs_cluster_encryption_at_rest_enabled.sql new file mode 100644 index 00000000..b1806a10 --- /dev/null +++ b/query/ecs/ecs_cluster_encryption_at_rest_enabled.sql @@ -0,0 +1,32 @@ +with unencrypted_volumes as ( + select + distinct cluster_arn + from + aws_ecs_container_instance as i, + aws_ec2_instance as e, + jsonb_array_elements(block_device_mappings) as b, + aws_ebs_volume as v + where + i.ec2_instance_id = e.instance_id + and b -> 'Ebs' ->> 'VolumeId' = v.volume_id + and not v.encrypted +) +select + -- Required Columns + c.cluster_arn as resource, + case + when c.registered_container_instances_count = 0 then 'skip' + when v.cluster_arn is not null then 'alarm' + else 'ok' + end as status, + case + when c.registered_container_instances_count = 0 then title || ' has no container instance registered.' + when v.cluster_arn is not null then c.title || ' encryption at rest disabled.' + else c.title || ' encryption at rest enabled.' + end as reason, + -- Additional Dimensions + c.region, + c.account_id +from + aws_ecs_cluster as c + left join unencrypted_volumes as v on v.cluster_arn = c.cluster_arn; \ No newline at end of file diff --git a/query/ecs/ecs_cluster_instance_in_vpc.sql b/query/ecs/ecs_cluster_instance_in_vpc.sql new file mode 100644 index 00000000..420c6162 --- /dev/null +++ b/query/ecs/ecs_cluster_instance_in_vpc.sql @@ -0,0 +1,17 @@ +select + -- Required Columns + c.arn as resource, + case + when i.vpc_id is null then 'alarm' + else 'ok' + end as status, + case + when i.vpc_id is null then c.title || ' not in VPC.' + else c.title || ' in VPC.' + end as reason, + -- Additional Dimensions + c.region, + c.account_id +from + aws_ecs_container_instance as c + left join aws_ec2_instance as i on c.ec2_instance_id = i.instance_id; \ No newline at end of file diff --git a/query/ecs/ecs_cluster_no_registered_container_instance.sql b/query/ecs/ecs_cluster_no_registered_container_instance.sql new file mode 100644 index 00000000..ff17fe53 --- /dev/null +++ b/query/ecs/ecs_cluster_no_registered_container_instance.sql @@ -0,0 +1,16 @@ +select + -- Required Columns + cluster_arn as resource, + case + when registered_container_instances_count = 0 then 'alarm' + else 'ok' + end as status, + case + when registered_container_instances_count = 0 then title || ' has no container instance registered.' + else title || ' has ' || registered_container_instances_count || ' container instance(s) registered.' + end as reason, + -- Additional Dimensions + region, + account_id +from + aws_ecs_cluster; \ No newline at end of file diff --git a/query/ecs/ecs_service_load_balancer_attached.sql b/query/ecs/ecs_service_load_balancer_attached.sql new file mode 100644 index 00000000..69301ce2 --- /dev/null +++ b/query/ecs/ecs_service_load_balancer_attached.sql @@ -0,0 +1,16 @@ +select + -- Required Columns + arn as resource, + case + when jsonb_array_length(load_balancers) = 0 then 'alarm' + else 'ok' + end as status, + case + when jsonb_array_length(load_balancers) = 0 then title || ' has no load balancer attached.' + else title || ' has ' || jsonb_array_length(load_balancers) || ' load balancer(s) attached.' + end as reason, + -- Additional Dimensions + region, + account_id +from + aws_ecs_service; \ No newline at end of file diff --git a/query/elb/elb_application_lb_listener_certificate_expire_30_days.sql b/query/elb/elb_application_lb_listener_certificate_expire_30_days.sql new file mode 100644 index 00000000..18f8e01c --- /dev/null +++ b/query/elb/elb_application_lb_listener_certificate_expire_30_days.sql @@ -0,0 +1,15 @@ +select + -- Required Columns + load_balancer_arn as resource, + case + when date(not_after) - date(current_date) >= 30 then 'ok' + else 'alarm' + end as status, + l.title || ' certificate set to expire in ' || extract(day from not_after - current_date) || ' days.' as reason, + -- Additional Dimensions + l.region, + l.account_id +from + aws_ec2_load_balancer_listener as l, + jsonb_array_elements(certificates) as c + left join aws_acm_certificate as a on c ->> 'CertificateArn' = a.certificate_arn; \ No newline at end of file diff --git a/query/elb/elb_application_lb_listener_certificate_expire_7_days.sql b/query/elb/elb_application_lb_listener_certificate_expire_7_days.sql new file mode 100644 index 00000000..b7b467d1 --- /dev/null +++ b/query/elb/elb_application_lb_listener_certificate_expire_7_days.sql @@ -0,0 +1,15 @@ +select + -- Required Columns + load_balancer_arn as resource, + case + when date(not_after) - date(current_date) >= 7 then 'ok' + else 'alarm' + end as status, + l.title || ' certificate set to expire in ' || extract(day from not_after - current_date) || ' days.' as reason, + -- Additional Dimensions + l.region, + l.account_id +from + aws_ec2_load_balancer_listener as l, + jsonb_array_elements(certificates) as c + left join aws_acm_certificate as a on c ->> 'CertificateArn' = a.certificate_arn; \ No newline at end of file diff --git a/query/elb/elb_application_network_lb_use_listeners.sql b/query/elb/elb_application_network_lb_use_listeners.sql new file mode 100644 index 00000000..58303ba3 --- /dev/null +++ b/query/elb/elb_application_network_lb_use_listeners.sql @@ -0,0 +1,34 @@ +with load_balancers as ( + select + n.arn, + n.title, + n.region, + n.account_id + from + aws_ec2_network_load_balancer as n + union + select + a.arn, + a.title, + a.region, + a.account_id + from + aws_ec2_application_load_balancer as a +) +select + -- Required Columns + distinct lb.arn as resource, + case + when l.load_balancer_arn is not null then 'ok' + else 'alarm' + end as status, + case + when l.load_balancer_arn is not null then lb.title || ' uses listener.' + else lb.title || ' does not uses listener.' + end as reason, + -- Additional Dimensions + lb.region, + lb.account_id +from + load_balancers as lb + left join aws_ec2_load_balancer_listener as l on lb.arn = l.load_balancer_arn; \ No newline at end of file diff --git a/query/elb/elb_network_lb_tls_listener_security_policy_configured.sql b/query/elb/elb_network_lb_tls_listener_security_policy_configured.sql new file mode 100644 index 00000000..fe2c40a8 --- /dev/null +++ b/query/elb/elb_network_lb_tls_listener_security_policy_configured.sql @@ -0,0 +1,40 @@ +with tls_listeners as ( + select + distinct load_balancer_arn + from + aws_ec2_load_balancer_listener + where + protocol = 'TLS' + and ssl_policy not in ('ELBSecurityPolicy-2016-08', 'ELBSecurityPolicy-FS-2018-0', 'ELBSecurityPolicy-TLS13-1-2-Ext1-2021-06', 'ELBSecurityPolicy-TLS13-1-2-2021-06') + group by + load_balancer_arn +), nwl_without_tls_listener as ( + select + load_balancer_arn, + count(*) + from + aws_ec2_load_balancer_listener + where + protocol = 'TLS' + group by + load_balancer_arn +) +select + -- Required Columns + lb.arn as resource, + case + when l.load_balancer_arn is not null and lb.arn in (select load_balancer_arn from tls_listeners) then 'alarm' + when l.load_balancer_arn is not null then 'ok' + else 'info' + end as status, + case + when l.load_balancer_arn is not null and lb.arn in (select load_balancer_arn from tls_listeners) then lb.title || ' TLS listener security policy not updated.' + when l.load_balancer_arn is not null then lb.title || ' TLS listener security policy updated.' + else lb.title || ' does not use TLS listener.' + end as reason, + -- Additional Dimensions + lb.region, + lb.account_id +from + aws_ec2_network_load_balancer as lb + left join nwl_without_tls_listener as l on l.load_balancer_arn = lb.arn; \ No newline at end of file diff --git a/query/elb/elb_tls_listener_protocol_version.sql b/query/elb/elb_tls_listener_protocol_version.sql new file mode 100644 index 00000000..e9b72a42 --- /dev/null +++ b/query/elb/elb_tls_listener_protocol_version.sql @@ -0,0 +1,18 @@ +select + -- Required Columns + load_balancer_arn as resource, + case + when protocol <> 'HTTPS' then 'skip' + when protocol = 'HTTPS' and ssl_policy like any(array['Protocol-SSLv3', 'Protocol-TLSv1']) then 'alarm' + else 'ok' + end as status, + case + when protocol <> 'HTTPS' then title || ' uses protocol ' || protocol || '.' + when ssl_policy like any (array['Protocol-SSLv3', 'Protocol-TLSv1']) then title || ' uses insecure SSL or TLS cipher.' + else title || ' uses secure SSL or TLS cipher.' + end as reason, + -- Additional Dimensions + region, + account_id +from + aws_ec2_load_balancer_listener; \ No newline at end of file diff --git a/query/emr/emr_account_public_access_blocked.sql b/query/emr/emr_account_public_access_blocked.sql new file mode 100644 index 00000000..0fa660de --- /dev/null +++ b/query/emr/emr_account_public_access_blocked.sql @@ -0,0 +1,16 @@ +select + -- Required Columns + 'arn:' || partition || '::' || region || ':' || account_id as resource, + case + when block_public_security_group_rules then 'ok' + else 'alarm' + end as status, + case + when block_public_security_group_rules then region || ' EMR block public access enabled.' + else region || ' EMR block public access disabled.' + end as reason, + -- Additional Dimensions + region, + account_id +from + aws_emr_block_public_access_configuration; \ No newline at end of file diff --git a/query/iam/iam_managed_policy_attached_to_role.sql b/query/iam/iam_managed_policy_attached_to_role.sql new file mode 100644 index 00000000..aea7ec93 --- /dev/null +++ b/query/iam/iam_managed_policy_attached_to_role.sql @@ -0,0 +1,23 @@ +with role_attached_policies as ( + select + jsonb_array_elements_text(attached_policy_arns) as policy_arn + from + aws_iam_role +) +select + -- Required Columns + p.arn as resource, + case + when p.arn in (select policy_arn from role_attached_policies) then 'ok' + else 'alarm' + end as status, + case + when p.arn in (select policy_arn from role_attached_policies) then title || ' attached to IAM role.' + else title || ' not attached to IAM role.' + end as reason, + -- Additional Dimensions + p.account_id +from + aws_iam_policy as p +where + is_aws_managed; \ No newline at end of file diff --git a/query/iam/iam_policy_unused.sql b/query/iam/iam_policy_unused.sql new file mode 100644 index 00000000..ebcd7a7c --- /dev/null +++ b/query/iam/iam_policy_unused.sql @@ -0,0 +1,33 @@ +with in_use_policies as ( + select + attached_policy_arns + from + aws_iam_user + union + select + attached_policy_arns + from + aws_iam_group + where + jsonb_array_length(users) > 0 + union + select + attached_policy_arns + from + aws_iam_role +) +select + -- Required Columns + arn as resource, + case + when arn in (select jsonb_array_elements_text(attached_policy_arns) from in_use_policies) then 'ok' + else 'alarm' + end as status, + case + when arn in (select jsonb_array_elements_text(attached_policy_arns) from in_use_policies) then title || ' in use.' + else title || ' not in use.' + end as reason, + -- Additional Dimensions + account_id +from + aws_iam_policy; \ No newline at end of file diff --git a/query/lambda/lambda_function_cors_configuration.sql b/query/lambda/lambda_function_cors_configuration.sql new file mode 100644 index 00000000..cb958d50 --- /dev/null +++ b/query/lambda/lambda_function_cors_configuration.sql @@ -0,0 +1,18 @@ +select + -- Required Columns + arn as resource, + case + when url_config is null then 'info' + when url_config -> 'Cors' ->> 'AllowOrigins' = '["*"]' then 'alarm' + else 'ok' + end as status, + case + when url_config is null then title || ' does not has a URL config.' + when url_config -> 'Cors' ->> 'AllowOrigins' = '["*"]' then title || ' CORS configuration allow all origins.' + else title || ' CORS configuration does not allow all origins.' + end as reason, + -- Additional Dimensions + region, + account_id +from + aws_lambda_function; \ No newline at end of file diff --git a/query/lambda/lambda_function_tracing_enabled.sql b/query/lambda/lambda_function_tracing_enabled.sql new file mode 100644 index 00000000..a4cdaeb0 --- /dev/null +++ b/query/lambda/lambda_function_tracing_enabled.sql @@ -0,0 +1,16 @@ +select + -- Required Columns + arn as resource, + case + when tracing_config ->> 'Mode' = 'PassThrough' then 'alarm' + else 'ok' + end as status, + case + when tracing_config ->> 'Mode' = 'PassThrough' then title || ' has tracing disabled.' + else title || ' has tracing enabled.' + end as reason, + -- Additional Dimensions + region, + account_id +from + aws_lambda_function; \ No newline at end of file diff --git a/query/route53/route53_domain_auto_renew_enabled.sql b/query/route53/route53_domain_auto_renew_enabled.sql new file mode 100644 index 00000000..b9de2726 --- /dev/null +++ b/query/route53/route53_domain_auto_renew_enabled.sql @@ -0,0 +1,16 @@ +select + -- Required Columns + arn as resource, + case + when auto_renew then 'ok' + else 'alarm' + end as status, + case + when auto_renew then title || ' auto renew enabled.' + else title || ' auto renew disabled.' + end as reason, + -- Additional Dimensions + region, + account_id +from + aws_route53_domain; \ No newline at end of file diff --git a/query/route53/route53_domain_expires_30_days.sql b/query/route53/route53_domain_expires_30_days.sql new file mode 100644 index 00000000..0966f1de --- /dev/null +++ b/query/route53/route53_domain_expires_30_days.sql @@ -0,0 +1,13 @@ +select + -- Required Columns + arn as resource, + case + when date(expiration_date) - date(current_date) >= 30 then 'ok' + else 'alarm' + end as status, + title || ' set to expire in ' || extract(day from expiration_date - current_date) || ' days.' as reason, + -- Additional Dimensions + region, + account_id +from + aws_route53_domain; \ No newline at end of file diff --git a/query/route53/route53_domain_expires_7_days.sql b/query/route53/route53_domain_expires_7_days.sql new file mode 100644 index 00000000..e1a2476c --- /dev/null +++ b/query/route53/route53_domain_expires_7_days.sql @@ -0,0 +1,13 @@ +select + -- Required Columns + arn as resource, + case + when date(expiration_date) - date(current_date) >= 7 then 'ok' + else 'alarm' + end as status, + title || ' set to expire in ' || extract(day from expiration_date - current_date) || ' days.' as reason, + -- Additional Dimensions + region, + account_id +from + aws_route53_domain; \ No newline at end of file diff --git a/query/route53/route53_domain_not_expired.sql b/query/route53/route53_domain_not_expired.sql new file mode 100644 index 00000000..d788f27c --- /dev/null +++ b/query/route53/route53_domain_not_expired.sql @@ -0,0 +1,16 @@ +select + -- Required Columns + arn as resource, + case + when expiration_date < (current_date - interval '1' minute) then 'alarm' + else 'ok' + end as status, + case + when expiration_date < (current_date - interval '1' minute) then title || ' expired on ' || to_char(expiration_date, 'DD-Mon-YYYY') || '.' + else title || ' set to expire in ' || extract(day from expiration_date - current_date) || ' days.' + end as reason, + -- Additional Dimensions + region, + account_id +from + aws_route53_domain; \ No newline at end of file diff --git a/query/route53/route53_domain_privacy_protection_enabled.sql b/query/route53/route53_domain_privacy_protection_enabled.sql new file mode 100644 index 00000000..0ec61751 --- /dev/null +++ b/query/route53/route53_domain_privacy_protection_enabled.sql @@ -0,0 +1,16 @@ +select + -- Required Columns + arn as resource, + case + when admin_privacy then 'ok' + else 'alarm' + end as status, + case + when admin_privacy then title || ' privacy protection enabled.' + else title || ' privacy protection disabled.' + end as reason, + -- Additional Dimensions + region, + account_id +from + aws_route53_domain; \ No newline at end of file diff --git a/query/s3/s3_bucket_acls_should_prohibit_user_access.sql b/query/s3/s3_bucket_acls_should_prohibit_user_access.sql index 8525a35b..af0f25a0 100644 --- a/query/s3/s3_bucket_acls_should_prohibit_user_access.sql +++ b/query/s3/s3_bucket_acls_should_prohibit_user_access.sql @@ -1,26 +1,29 @@ with bucket_acl_details as ( - select - arn, + select + arn, title, array[acl -> 'Owner' ->> 'ID'] as bucket_owner, array_agg(grantee_id) as bucket_acl_permissions, + object_ownership_controls, region, account_id from aws_s3_bucket, - jsonb_path_query(acl, '$.Grants.Grantee.ID') as grantee_id + jsonb_path_query(acl, '$.Grants.Grantee.ID') as grantee_id group by arn, title, acl, region, - account_id + account_id, + object_ownership_controls ), bucket_acl_checks as ( select arn, title, to_jsonb(bucket_acl_permissions) - bucket_owner as additional_permissions, + object_ownership_controls, region, account_id from @@ -30,11 +33,13 @@ select -- Required Columns arn as resource, case + when object_ownership_controls -> 'Rules' @> '[{"ObjectOwnership": "BucketOwnerEnforced"} ]' then 'ok' when jsonb_array_length(additional_permissions) = 0 then 'ok' else 'alarm' end status, case - when jsonb_array_length(additional_permissions) = 0 then title || ' does not have ACLs for user access.' + when object_ownership_controls -> 'Rules' @> '[{"ObjectOwnership": "BucketOwnerEnforced"} ]' then title || ' ACLs are disabled.' + when jsonb_array_length(additional_permissions) = 0 then title || ' does not have ACLs for user access.' else title || ' has ACLs for user access.' end reason, -- Additional Dimensions diff --git a/query/s3/s3_bucket_restrict_public_read_access.sql b/query/s3/s3_bucket_restrict_public_read_access.sql index 45c61356..49419601 100644 --- a/query/s3/s3_bucket_restrict_public_read_access.sql +++ b/query/s3/s3_bucket_restrict_public_read_access.sql @@ -1,25 +1,51 @@ -with data as ( +with public_acl as ( select distinct name from aws_s3_bucket, jsonb_array_elements(acl -> 'Grants') as grants where - grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AllUsers' + (grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AllUsers' + or grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers') and ( grants ->> 'Permission' = 'FULL_CONTROL' or grants ->> 'Permission' = 'READ_ACP' + or grants ->> 'Permission' = 'READ' ) - ) + ),read_access_policy as ( + select + distinct name + from + aws_s3_bucket, + jsonb_array_elements(policy_std -> 'Statement') as s, + jsonb_array_elements_text(s -> 'Action') as action + where + s ->> 'Effect' = 'Allow' + and ( + s -> 'Principal' -> 'AWS' = '["*"]' + or s ->> 'Principal' = '*' + ) + and ( + action = '*' + or action = '*:*' + or action = 's3:*' + or action ilike 's3:get%' + or action ilike 's3:list%' + ) +) select -- Required Columns b.arn as resource, case - when d.name is null then 'ok' + when (block_public_acls or a.name is null) and not bucket_policy_is_public then 'ok' + when (block_public_acls or a.name is null) and (bucket_policy_is_public and block_public_policy) then 'ok' + when (block_public_acls or a.name is null) and (bucket_policy_is_public and p.name is null) then 'ok' else 'alarm' end status, case - when d.name is null then b.title || ' not publicly readable.' + when (block_public_acls or a.name is null) and not bucket_policy_is_public then b.title || ' not publicly readable.' + when (block_public_acls or a.name is null) and (bucket_policy_is_public and block_public_policy) then b.title || ' not publicly readable.' + when (block_public_acls or a.name is null) and (bucket_policy_is_public and p.name is null) then b.title || ' not publicly readable.' else b.title || ' publicly readable.' end reason, -- Additional Dimensions @@ -27,4 +53,5 @@ select b.account_id from aws_s3_bucket as b - left join data as d on b.name = d.name; \ No newline at end of file + left join public_acl as a on b.name = a.name + left join read_access_policy as p on b.name = p.name; \ No newline at end of file diff --git a/query/s3/s3_bucket_restrict_public_write_access.sql b/query/s3/s3_bucket_restrict_public_write_access.sql index 0c9fbcf6..845ad912 100644 --- a/query/s3/s3_bucket_restrict_public_write_access.sql +++ b/query/s3/s3_bucket_restrict_public_write_access.sql @@ -1,25 +1,56 @@ -with data as ( +with public_acl as ( select distinct name from aws_s3_bucket, jsonb_array_elements(acl -> 'Grants') as grants where - grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AllUsers' + (grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AllUsers' + or grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers') and ( grants ->> 'Permission' = 'FULL_CONTROL' or grants ->> 'Permission' = 'WRITE_ACP' + or grants ->> 'Permission' = 'WRITE' ) - ) +), write_access_policy as ( + select + distinct name + from + aws_s3_bucket, + jsonb_array_elements(policy_std -> 'Statement') as s, + jsonb_array_elements_text(s -> 'Action') as action + where + s ->> 'Effect' = 'Allow' + and ( + s -> 'Principal' -> 'AWS' = '["*"]' + or s ->> 'Principal' = '*' + ) + and ( + action = '*' + or action = '*:*' + or action = 's3:*' + or action ilike 's3:put%' + or action ilike 's3:delete%' + or action ilike 's3:create%' + or action ilike 's3:update%' + or action ilike 's3:replicate%' + or action ilike 's3:restore%' + ) +) select -- Required Columns b.arn as resource, + bucket_policy_is_public, case - when d.name is null then 'ok' + when (block_public_acls or a.name is null) and not bucket_policy_is_public then 'ok' + when (block_public_acls or a.name is null) and (bucket_policy_is_public and block_public_policy) then 'ok' + when bucket_policy_is_public and p.name is null then 'ok' else 'alarm' end status, case - when d.name is null then b.title || ' not publicly writable.' + when (block_public_acls or a.name is null ) and not bucket_policy_is_public then b.title || ' not publicly writable.' + when (block_public_acls or a.name is null) and (bucket_policy_is_public and block_public_policy) then b.title || ' not publicly writable.' + when (block_public_acls or a.name is null) and (bucket_policy_is_public and p.name is null) then b.title || ' not publicly writable.' else b.title || ' publicly writable.' end reason, -- Additional Dimensions @@ -27,4 +58,5 @@ select b.account_id from aws_s3_bucket as b - left join data as d on b.name = d.name; \ No newline at end of file + left join public_acl as a on b.name = a.name + left join write_access_policy as p on b.name = p.name \ No newline at end of file diff --git a/query/s3/s3_bucket_static_website_hosting_disabled.sql b/query/s3/s3_bucket_static_website_hosting_disabled.sql new file mode 100644 index 00000000..44ae44af --- /dev/null +++ b/query/s3/s3_bucket_static_website_hosting_disabled.sql @@ -0,0 +1,16 @@ +select + -- Required Columns + arn as resource, + case + when website_configuration -> 'IndexDocument' ->> 'Suffix' is not null then 'alarm' + else 'ok' + end status, + case + when website_configuration -> 'IndexDocument' ->> 'Suffix' is not null then name || ' static website hosting enabled.' + else name || ' static website hosting disabled.' + end reason, + -- Additional Dimensions + region, + account_id +from + aws_s3_bucket; \ No newline at end of file diff --git a/query/s3/s3_public_access_block_account.sql b/query/s3/s3_public_access_block_account.sql index 14c0c43b..17e00725 100644 --- a/query/s3/s3_public_access_block_account.sql +++ b/query/s3/s3_public_access_block_account.sql @@ -15,7 +15,7 @@ select and ignore_public_acls and restrict_public_buckets then 'Account level public access blocks enabled.' - else 'Account level public access not enabled for: ' || + else 'Account level public access blocks not enabled for: ' || concat_ws(', ', case when not (block_public_acls ) then 'block_public_acls' end, case when not (block_public_policy) then 'block_public_policy' end, diff --git a/query/sagemaker/sagemaker_notebook_instance_encrypted_with_kms_cmk.sql b/query/sagemaker/sagemaker_notebook_instance_encrypted_with_kms_cmk.sql new file mode 100644 index 00000000..cec7d0b6 --- /dev/null +++ b/query/sagemaker/sagemaker_notebook_instance_encrypted_with_kms_cmk.sql @@ -0,0 +1,19 @@ +select + -- Required Columns + i.arn as resource, + case + when kms_key_id is null then 'alarm' + when k.key_manager = 'CUSTOMER' then 'ok' + else 'alarm' + end as status, + case + when kms_key_id is null then i.title || ' encryption disabled.' + when k.key_manager = 'CUSTOMER' then i.title || ' encryption at rest with CMK enabled.' + else i.title || ' encryption at rest with CMK disabled.' + end as reason, + -- Additional Dimensions + i.region, + i.account_id +from + aws_sagemaker_notebook_instance as i + left join aws_kms_key as k on k.arn = i.kms_key_id; \ No newline at end of file diff --git a/query/vpc/vpc_security_group_restrict_ingress_kafka_port.sql b/query/vpc/vpc_security_group_restrict_ingress_kafka_port.sql new file mode 100644 index 00000000..d467dd42 --- /dev/null +++ b/query/vpc/vpc_security_group_restrict_ingress_kafka_port.sql @@ -0,0 +1,41 @@ +with ingress_kafka_port as ( + select + group_id, + count(*) as num_ssh_rules + from + aws_vpc_security_group_rule + where + type = 'ingress' + and ( + cidr_ipv4 = '0.0.0.0/0' + or cidr_ipv6 = '::/0' + ) + and ( + ( ip_protocol = '-1' + and from_port is null + ) + or ( + from_port >= 9092 + and to_port <= 9092 + ) + ) + group by + group_id +) +select + -- Required Columns + arn as resource, + case + when k.group_id is null then 'ok' + else 'alarm' + end as status, + case + when k.group_id is null then sg.group_id || ' ingress restricted for kafka port from 0.0.0.0/0.' + else sg.group_id || ' contains ' || k.num_ssh_rules || ' ingress rule(s) allowing kafka port from 0.0.0.0/0.' + end as reason, + -- Additional Dimensions + sg.region, + sg.account_id +from + aws_vpc_security_group as sg + left join ingress_kafka_port as k on k.group_id = sg.group_id; diff --git a/query/vpc/vpc_security_group_restrict_kibana_port.sql b/query/vpc/vpc_security_group_restrict_ingress_kibana_port.sql similarity index 100% rename from query/vpc/vpc_security_group_restrict_kibana_port.sql rename to query/vpc/vpc_security_group_restrict_ingress_kibana_port.sql