diff --git a/transformations/aws/compliance-free/README.md b/transformations/aws/compliance-free/README.md index 6bbeaecca..d6cb81f4d 100644 --- a/transformations/aws/compliance-free/README.md +++ b/transformations/aws/compliance-free/README.md @@ -100,6 +100,16 @@ The free version contains 10% of the full pack's checks. - ✅ `1.8`: `password_policy_min_length` - ✅ `1.9`: `password_policy_prevent_reuse` +##### `cis_v3.0.0` + +- ✅ `1.2`: `security_account_information_provided` +- ✅ `1.4`: `iam_root_user_no_access_keys` +- ✅ `1.5`: `mfa_enabled_for_root` +- ✅ `1.6`: `hardware_mfa_enabled_for_root` +- ✅ `1.7`: `iam_root_last_used` +- ✅ `1.8`: `password_policy_min_length` +- ✅ `1.9`: `password_policy_prevent_reuse` + ##### `foundational_security` - ✅ `apigateway.1`: `api_gw_execution_logging_enabled` diff --git a/transformations/aws/compliance-free/models/aws_compliance__cis_v3_0_0_free.sql b/transformations/aws/compliance-free/models/aws_compliance__cis_v3_0_0_free.sql new file mode 100644 index 000000000..b1dcd03a6 --- /dev/null +++ b/transformations/aws/compliance-free/models/aws_compliance__cis_v3_0_0_free.sql @@ -0,0 +1,20 @@ +with + aggregated as ( + ({{ security_account_information_provided('cis_v3.0.0','1.2') }}) + {{ union() }} + ({{ iam_root_user_no_access_keys('cis_v3.0.0','1.4') }}) + {{ union() }} + ({{ mfa_enabled_for_root('cis_v3.0.0','1.5') }}) + {{ union() }} + ({{ hardware_mfa_enabled_for_root('cis_v3.0.0','1.6') }}) + {{ union() }} + ({{ iam_root_last_used('cis_v3.0.0','1.7') }}) + {{ union() }} + ({{ password_policy_min_length('cis_v3.0.0','1.8') }}) + {{ union() }} + ({{ password_policy_prevent_reuse('cis_v3.0.0','1.9') }}) + ) +select + {{ gen_timestamp() }}, + aggregated.* +from aggregated diff --git a/transformations/aws/compliance-free/requirements.txt b/transformations/aws/compliance-free/requirements.txt index 2ba5742d0..a1fb7560c 100644 --- a/transformations/aws/compliance-free/requirements.txt +++ b/transformations/aws/compliance-free/requirements.txt @@ -1,3 +1,4 @@ dbt-postgres==1.7.10 dbt-bigquery==1.7.6 dbt-snowflake==1.7.2 +pyarrow >= 3.0.0 \ No newline at end of file diff --git a/transformations/aws/compliance-premium/README.md b/transformations/aws/compliance-premium/README.md index 0b5876e86..6763ae6d7 100644 --- a/transformations/aws/compliance-premium/README.md +++ b/transformations/aws/compliance-premium/README.md @@ -164,6 +164,67 @@ The premium version contains all checks. - ✅ `5.4`: `default_sg_no_access` - ✅ `5.6`: `ec2_not_imdsv2_instances` +##### `cis_v3.0.0` + +- ✅ `1.2`: `security_account_information_provided` +- ✅ `1.4`: `iam_root_user_no_access_keys` +- ✅ `1.5`: `mfa_enabled_for_root` +- ✅ `1.6`: `hardware_mfa_enabled_for_root` +- ✅ `1.7`: `iam_root_last_used` +- ✅ `1.8`: `password_policy_min_length` +- ✅ `1.9`: `password_policy_prevent_reuse` +- ✅ `1.10`: `mfa_enabled_for_console_access` +- ✅ `1.11`: `iam_user_access_keys_and_password_at_setup` +- ✅ `1.12`: `unused_creds_disabled_45_days` +- ✅ `1.13`: `users_with_two_active_access_keys` +- ✅ `1.14`: `old_access_keys` +- ✅ `1.15`: `policies_attached_to_groups_roles` +- ✅ `1.16`: `no_star` +- ✅ `1.17`: `iam_support_role` +- ✅ `1.18`: `use_iam_roles_for_instances` +- ✅ `1.19`: `iam_server_certificate_not_expired` +- ✅ `1.20`: `regions_with_no_accessanalyzers` +- ✅ `1.21`: `iam_users_are_managed_centrally` +- ✅ `1.22`: `iam_user_group_role_cloudshell_fullaccess_restricted` +- ✅ `2.1.1`: `deny_http_requests` +- ✅ `2.1.2`: `mfa_delete` +- ✅ `2.1.4`: `account_level_public_access_blocks` +- ✅ `2.2.1`: `unencrypted_ebs_volumes` +- ✅ `2.3.1`: `instances_should_have_ecnryption_at_rest_enabled` +- ✅ `2.3.2`: `redis_clusters_have_autominorversionupgrade` +- ✅ `2.3.3`: `rds_db_instances_should_prohibit_public_access` +- ✅ `2.4.1`: `unencrypted_efs_filesystems` +- ✅ `3.1`: `cloudtrail_enabled_all_regions` +- ✅ `3.2`: `log_file_validation_enabled` +- ✅ `3.3`: `config_enabled_all_regions` +- ✅ `3.4`: `bucket_access_logging` +- ✅ `3.5`: `logs_encrypted` +- ✅ `3.6`: `rotation_enabled_for_customer_key` +- ✅ `3.7`: `flow_logs_enabled_in_all_vpcs` +- ✅ `3.8`: `cloudtrail_s3_object_write_events_audit_enabled` +- ✅ `3.9`: `cloudtrail_s3_object_read_events_audit_enabled` +- ✅ `4.1`: `alarm_unauthorized_api` +- ✅ `4.2`: `alarm_console_no_mfa` +- ✅ `4.3`: `alarm_root_account` +- ✅ `4.4`: `alarm_iam_policy_change` +- ✅ `4.5`: `alarm_cloudtrail_config_changes` +- ✅ `4.6`: `alarm_console_auth_failure` +- ✅ `4.7`: `alarm_delete_customer_cmk` +- ✅ `4.8`: `alarm_s3_bucket_policy_change` +- ✅ `4.9`: `alarm_aws_config_changes` +- ✅ `4.10`: `alarm_security_group_changes` +- ✅ `4.11`: `alarm_nacl_changes` +- ✅ `4.12`: `alarm_network_gateways` +- ✅ `4.13`: `alarm_route_table_changes` +- ✅ `4.14`: `alarm_vpc_changes` +- ✅ `4.15`: `alarm_organization_changes` +- ✅ `4.16`: `securityhub_enabled` +- ✅ `5.1`: `vpc_network_acl_remote_administration` +- ✅ `5.2`: `vpc_security_group_remote_administration_ipv4` +- ✅ `5.3`: `no_broad_public_ipv6_ingress_on_port_22_3389` +- ✅ `5.4`: `default_sg_no_access` +- ✅ `5.6`: `ec2_not_imdsv2_instances` + ##### `foundational_security` - ✅ `account.1`: `security_account_information_provided` diff --git a/transformations/aws/compliance-premium/models/aws_compliance__cis_v3_0_0.sql b/transformations/aws/compliance-premium/models/aws_compliance__cis_v3_0_0.sql new file mode 100644 index 000000000..4743ef3a0 --- /dev/null +++ b/transformations/aws/compliance-premium/models/aws_compliance__cis_v3_0_0.sql @@ -0,0 +1,122 @@ +with + aggregated as ( + ({{ security_account_information_provided('cis_v3.0.0','1.2') }}) + {{ union() }} + ({{ iam_root_user_no_access_keys('cis_v3.0.0','1.4') }}) + {{ union() }} + ({{ mfa_enabled_for_root('cis_v3.0.0','1.5') }}) + {{ union() }} + ({{ hardware_mfa_enabled_for_root('cis_v3.0.0','1.6') }}) + {{ union() }} + ({{ iam_root_last_used('cis_v3.0.0','1.7') }}) + {{ union() }} + ({{ password_policy_min_length('cis_v3.0.0','1.8') }}) + {{ union() }} + ({{ password_policy_prevent_reuse('cis_v3.0.0','1.9') }}) + {{ union() }} + ({{ mfa_enabled_for_console_access('cis_v3.0.0','1.10') }}) + {{ union() }} + ({{ iam_user_access_keys_and_password_at_setup('cis_v3.0.0','1.11') }}) + {{ union() }} + ({{ unused_creds_disabled_45_days('cis_v3.0.0','1.12') }}) + {{ union() }} + ({{ users_with_two_active_access_keys('cis_v3.0.0','1.13') }}) + {{ union() }} + ({{ old_access_keys('cis_v3.0.0','1.14') }}) + {{ union() }} + ({{ policies_attached_to_groups_roles('cis_v3.0.0','1.15') }}) + {{ union() }} + ({{ no_star('cis_v3.0.0','1.16') }}) + {{ union() }} + ({{ iam_support_role('cis_v3.0.0','1.17') }}) + {{ union() }} + ({{ use_iam_roles_for_instances('cis_v3.0.0','1.18') }}) + {{ union() }} + ({{ iam_server_certificate_not_expired('cis_v3.0.0','1.19') }}) + {{ union() }} + ({{ regions_with_no_accessanalyzers('cis_v3.0.0','1.20') }}) + {{ union() }} + ({{ iam_users_are_managed_centrally('cis_v3.0.0','1.21') }}) + {{ union() }} + ({{ iam_user_group_role_cloudshell_fullaccess_restricted('cis_v3.0.0','1.22') }}) + {{ union() }} + ({{ deny_http_requests('cis_v3.0.0','2.1.1') }}) + {{ union() }} + ({{ mfa_delete('cis_v3.0.0','2.1.2') }}) + {{ union() }} + ({{ account_level_public_access_blocks('cis_v3.0.0','2.1.4') }}) + {{ union() }} + ({{ unencrypted_ebs_volumes('cis_v3.0.0','2.2.1') }}) + {{ union() }} + ({{ instances_should_have_ecnryption_at_rest_enabled('cis_v3.0.0','2.3.1') }}) + {{ union() }} + ({{ redis_clusters_have_autominorversionupgrade('cis_v3.0.0','2.3.2') }}) + {{ union() }} + ({{ rds_db_instances_should_prohibit_public_access('cis_v3.0.0','2.3.3') }}) + {{ union() }} + ({{ unencrypted_efs_filesystems('cis_v3.0.0','2.4.1') }}) + {{ union() }} + ({{ cloudtrail_enabled_all_regions('cis_v3.0.0','3.1') }}) + {{ union() }} + ({{ log_file_validation_enabled('cis_v3.0.0','3.2') }}) + {{ union() }} + ({{ config_enabled_all_regions('cis_v3.0.0','3.3') }}) + {{ union() }} + ({{ bucket_access_logging('cis_v3.0.0','3.4') }}) + {{ union() }} + ({{ logs_encrypted('cis_v3.0.0','3.5') }}) + {{ union() }} + ({{ rotation_enabled_for_customer_key('cis_v3.0.0','3.6') }}) + {{ union() }} + ({{ flow_logs_enabled_in_all_vpcs('cis_v3.0.0','3.7') }}) + {{ union() }} + ({{ cloudtrail_s3_object_write_events_audit_enabled('cis_v3.0.0','3.8') }}) + {{ union() }} + ({{ cloudtrail_s3_object_read_events_audit_enabled('cis_v3.0.0','3.9') }}) + {{ union() }} + ({{ alarm_unauthorized_api('cis_v3.0.0','4.1') }}) + {{ union() }} + ({{ alarm_console_no_mfa('cis_v3.0.0','4.2') }}) + {{ union() }} + ({{ alarm_root_account('cis_v3.0.0','4.3') }}) + {{ union() }} + ({{ alarm_iam_policy_change('cis_v3.0.0','4.4') }}) + {{ union() }} + ({{ alarm_cloudtrail_config_changes('cis_v3.0.0','4.5') }}) + {{ union() }} + ({{ alarm_console_auth_failure('cis_v3.0.0','4.6') }}) + {{ union() }} + ({{ alarm_delete_customer_cmk('cis_v3.0.0','4.7') }}) + {{ union() }} + ({{ alarm_s3_bucket_policy_change('cis_v3.0.0','4.8') }}) + {{ union() }} + ({{ alarm_aws_config_changes('cis_v3.0.0','4.9') }}) + {{ union() }} + ({{ alarm_security_group_changes('cis_v3.0.0','4.10') }}) + {{ union() }} + ({{ alarm_nacl_changes('cis_v3.0.0','4.11') }}) + {{ union() }} + ({{ alarm_network_gateways('cis_v3.0.0','4.12') }}) + {{ union() }} + ({{ alarm_route_table_changes('cis_v3.0.0','4.13') }}) + {{ union() }} + ({{ alarm_vpc_changes('cis_v3.0.0','4.14') }}) + {{ union() }} + ({{ alarm_organization_changes('cis_v3.0.0','4.15') }}) + {{ union() }} + ({{ securityhub_enabled('cis_v3.0.0','4.16') }}) + {{ union() }} + ({{ vpc_network_acl_remote_administration('cis_v3.0.0','5.1') }}) + {{ union() }} + ({{ vpc_security_group_remote_administration_ipv4('cis_v3.0.0','5.2') }}) + {{ union() }} + ({{ no_broad_public_ipv6_ingress_on_port_22_3389('cis_v3.0.0','5.3') }}) + {{ union() }} + ({{ default_sg_no_access('cis_v3.0.0','5.4') }}) + {{ union() }} + ({{ ec2_not_imdsv2_instances('cis_v3.0.0','5.6') }}) + ) +select + {{ gen_timestamp() }}, + aggregated.* +from aggregated diff --git a/transformations/aws/compliance-premium/requirements.txt b/transformations/aws/compliance-premium/requirements.txt index 2ba5742d0..a1fb7560c 100644 --- a/transformations/aws/compliance-premium/requirements.txt +++ b/transformations/aws/compliance-premium/requirements.txt @@ -1,3 +1,4 @@ dbt-postgres==1.7.10 dbt-bigquery==1.7.6 dbt-snowflake==1.7.2 +pyarrow >= 3.0.0 \ No newline at end of file diff --git a/transformations/aws/macros/config/config_enabled_all_regions.sql b/transformations/aws/macros/config/config_enabled_all_regions.sql index 17455fcb5..56ec72d49 100644 --- a/transformations/aws/macros/config/config_enabled_all_regions.sql +++ b/transformations/aws/macros/config/config_enabled_all_regions.sql @@ -3,57 +3,101 @@ {% endmacro %} {% macro snowflake__config_enabled_all_regions(framework, check_id) %} +with global_recorders as ( + select + count(*) as global_config_recorders + from + aws_config_configuration_recorders + where + recording_group:IncludeGlobalResourceTypes::BOOLEAN = TRUE + and recording_group:AllSupported::BOOLEAN = TRUE + and status_recording = TRUE + and status_last_status = 'SUCCESS' +) select - '{{framework}}' As framework, - '{{check_id}}' As check_id, + '{{framework}}' As framework, + '{{check_id}}' As check_id, 'AWS Config should be enabled' as title, - account_id, - arn as resource_id, - CASE - WHEN ((recording_group:IncludeGlobalResourceTypes::BOOLEAN != TRUE) OR (recording_group:AllSupported::BOOLEAN != TRUE) OR (status_recording != TRUE OR status_last_status != 'SUCCESS')) - THEN 'fail' - ELSE 'pass' - END AS status -FROM - aws_config_configuration_recorders + r.account_id, + r.arn as resource_id, + case + when g.global_config_recorders >= 1 + and status_recording = TRUE + and status_last_status = 'SUCCESS' then 'pass' + else 'fail' + end as status +from + global_recorders g, + aws_regions a + inner join aws_config_configuration_recorders as r on r.account_id = a.account_id + and r.region = a.region_name + where a.opt_in_status != 'not-opted-in' {% endmacro %} {% macro postgres__config_enabled_all_regions(framework, check_id) %} +with global_recorders as ( + select + count(*) as global_config_recorders + from + aws_config_configuration_recorders + where + recording_group -> 'IncludeGlobalResourceTypes' = 'true' + and recording_group -> 'AllSupported' = 'true' + and status_recording is true + and status_last_status = 'SUCCESS' +) select - '{{framework}}' as framework, - '{{check_id}}' as check_id, + '{{framework}}' As framework, + '{{check_id}}' As check_id, 'AWS Config should be enabled' as title, - account_id, - arn as resource_id, - case when - (recording_group->>'IncludeGlobalResourceTypes')::boolean IS NOT TRUE - OR (recording_group->>'AllSupported')::boolean IS NOT TRUE - OR status_recording IS NOT TRUE - OR status_last_status IS DISTINCT FROM 'SUCCESS' - then 'fail' - else 'pass' - end as status -FROM - aws_config_configuration_recorders + r.account_id, + r.arn as resource_id, + case + when g.global_config_recorders >= 1 + and status_recording is true + and status_last_status = 'SUCCESS' then 'pass' + else 'fail' + end as status +from + global_recorders g, + aws_regions a + inner join aws_config_configuration_recorders r on r.account_id = a.account_id + and r.region = a.region_name + where a.opt_in_status != 'not-opted-in' {% endmacro %} {% macro default__config_enabled_all_regions(framework, check_id) %}{% endmacro %} {% macro bigquery__config_enabled_all_regions(framework, check_id) %} +with global_recorders as ( + select + count(*) as global_config_recorders + from + {{ full_table_name("aws_config_configuration_recorders") }} + where + CAST( JSON_VALUE(recording_group.IncludeGlobalResourceTypes) AS BOOL) IS TRUE + and CAST( JSON_VALUE(recording_group.AllSupported) AS BOOL) IS TRUE + and status_recording is true + and status_last_status = 'SUCCESS' +) select + distinct '{{framework}}' as framework, '{{check_id}}' as check_id, 'AWS Config should be enabled' as title, - account_id, - arn as resource_id, - case when - CAST( JSON_VALUE(recording_group.IncludeGlobalResourceTypes) AS BOOL) IS NOT TRUE - OR CAST( JSON_VALUE(recording_group.AllSupported) AS BOOL) IS NOT TRUE - OR status_recording IS NOT TRUE - OR status_last_status IS DISTINCT FROM 'SUCCESS' - then 'fail' - else 'pass' - end as status -FROM - {{ full_table_name("aws_config_configuration_recorders") }} + r.account_id, + r.arn as resource_id, + case + when a.opt_in_status = 'not-opted-in' then '' + when g.global_config_recorders >= 1 + and status_recording is true + and status_last_status = 'SUCCESS' then 'pass' + else 'fail' + end as status +from + global_recorders g, + {{ full_table_name("aws_regions") }} a + inner join {{ full_table_name("aws_config_configuration_recorders") }} r on r.account_id = a.account_id + and r.region = a.region_name + where a.opt_in_status != 'not-opted-in' {% endmacro %} \ No newline at end of file