From a2f23f0dd0e7e81d3e25fd0029999c6762c49faa Mon Sep 17 00:00:00 2001 From: ronsh12 <101520407+ronsh12@users.noreply.github.com> Date: Wed, 3 Jan 2024 19:29:30 +0200 Subject: [PATCH] feat: Added queries for AWS Foundational Security for Postgres - Premium (#451) * feat: Added queries for AWS Foundational Security for Postgres - Premium * Change postgres version from 11 to 15 * Upated query neptune_cluster_snapshot_public_prohibited * Changed queries --- .../aws_compliance__foundational_security.sql | 4 +- .../security_account_information_provided.sql | 1 + ...y_length_should_be_more_than_2048_bits.sql | 22 ++++ ...stage_should_have_xray_tracing_enabled.sql | 21 ++++ .../api_gw_stage_should_use_ssl.sql | 21 ++++ .../appsync_should_have_logging_turned_on.sql | 22 ++++ .../athena_workgroup_encrypted_at_rest.sql | 19 +++ ...scaling_group_elb_healthcheck_required.sql | 23 ++++ .../autoscaling_launch_config_hop_limit.sql | 22 ++++ ...aling_launch_config_public_ip_disabled.sql | 22 ++++ .../autoscaling_launch_template.sql | 22 ++++ ...toscaling_launchconfig_requires_imdsv2.sql | 22 ++++ .../autoscaling/autoscaling_multiple_az.sql | 22 ++++ .../autoscaling_multiple_instance_types.sql | 29 +++++ ...loudformation_stack_notification_check.sql | 22 ++++ ...ould_encrypt_traffic_to_custom_origins.sql | 49 ++++++++ ...d_not_point_to_non_existent_s3_origins.sql | 46 ++++++- ...hould_not_use_depricated_ssl_protocols.sql | 36 +++++- ...ution_should_use_origin_access_control.sql | 45 +++++++ .../distribution_should_use_sni.sql | 21 ++++ ...bution_should_use_ssl_tls_certificates.sql | 25 ++++ .../origin_access_identity_enabled.sql | 21 ++++ .../logs_file_validation_enabled.sql | 20 +++ ...ironment_has_logging_aws_configuration.sql | 22 ++++ ...onment_should_not_have_privileged_mode.sql | 20 +++ .../macros/codebuild/s3_logs_encrypted.sql | 20 +++ .../clusters_should_be_encrypted_at_rest.sql | 20 +++ ...rs_should_have_7_days_backup_retention.sql | 20 +++ .../ec2/both_vpn_channels_should_be_up.sql | 33 ++++- ..._templates_should_not_assign_public_ip.sql | 39 +++++- ...ld_not_allow_ingress_for_ssh_rdp_ports.sql | 45 ++++++- .../aws/macros/ec2/not_imdsv2_instances.sql | 21 ++++ ...ravirtual_instances_should_not_be_used.sql | 20 +++ .../ec2/security_groups_not_associated.sql | 33 ++++- ...should_not_auto_accept_vpc_attachments.sql | 20 +++ ...itories_have_image_scanning_configured.sql | 21 ++++ ...ories_have_tag_immutability_configured.sql | 21 ++++ ...ies_have_at_least_one_lifecycle_policy.sql | 23 ++++ ...clusters_should_use_container_insights.sql | 34 +++++ ...ers_limited_read_only_root_filesystems.sql | 36 ++++++ ...ontainers_should_run_as_non_privileged.sql | 36 ++++++ .../fargate_should_run_on_latest_version.sql | 27 ++++ ...should_not_be_in_environment_variables.sql | 41 ++++++ ...itions_should_not_share_host_namespace.sql | 23 ++++ ...ster_endpoints_not_publicly_accessible.sql | 20 +++ ...d_run_on_supported_kuberneters_version.sql | 20 +++ ...rs_should_not_use_default_subnet_group.sql | 21 ++++ ..._clusters_have_autominorversionupgrade.sql | 23 ++++ ...clusters_should_have_automatic_backups.sql | 23 ++++ ...tion_groups_automatic_failover_enabled.sql | 21 ++++ ...s_replication_groups_encrypted_at_rest.sql | 21 ++++ ...eplication_groups_encrypted_in_transit.sql | 21 ++++ ...cation_groups_under_version_6_use_auth.sql | 23 ++++ ...ic_beanstalk_stream_logs_to_cloudwatch.sql | 37 ++++++ ..._migration_mode_defensive_or_strictest.sql | 26 +++- .../elbv1_have_cross_zone_load_balancing.sql | 23 +++- ...elbv1_have_multiple_availability_zones.sql | 23 +++- .../elb/elbv1_https_predefined_policy.sql | 1 - ..._migration_mode_defensive_or_strictest.sql | 21 ++++ ...elbv2_have_multiple_availability_zones.sql | 23 +++- .../kinesis/kinesis_stream_encrypted.sql | 19 +++ .../iam_customer_policy_no_kms_decrypt.sql | 1 - .../kms/iam_inline_policy_no_kms_decrypt.sql | 117 +++++++++++++++++- .../aws/macros/kms/key_rotation_enabled.sql | 21 ++++ .../kms/keys_not_unintentionally_deleted.sql | 21 ++++ ...mbda_function_public_access_prohibited.sql | 30 +++++ .../aws/macros/lambda/lambda_inside_vpc.sql | 24 ++++ .../lambda/lambda_vpc_multi_az_check.sql | 27 ++++ ...neptune_cluster_backup_retention_check.sql | 23 ++++ ..._cluster_cloudwatch_log_export_enabled.sql | 21 ++++ ..._cluster_copy_tags_to_snapshot_enabled.sql | 21 ++++ ...ne_cluster_deletion_protection_enabled.sql | 21 ++++ .../neptune/neptune_cluster_encrypted.sql | 21 ++++ ...ne_cluster_iam_database_authentication.sql | 21 ++++ .../neptune_cluster_snapshot_encrypted.sql | 21 ++++ ...une_cluster_snapshot_public_prohibited.sql | 23 ++++ ...policy_default_action_fragment_packets.sql | 22 ++++ ...tfw_policy_default_action_full_packets.sql | 22 ++++ .../netfw_policy_rule_group_associated.sql | 21 ++++ .../netfw_stateless_rule_group_not_empty.sql | 28 ++++- ..._snapshots_should_be_encrypted_at_rest.sql | 29 +++++ ...igured_for_multiple_availability_zones.sql | 17 +++ ...e_configured_to_copy_tags_to_snapshots.sql | 17 +++ ...hould_have_deletion_protection_enabled.sql | 17 +++ ...d_not_use_database_engine_default_port.sql | 39 ++++++ .../macros/rds/db_instance_backup_enabled.sql | 22 ++++ ..._configured_for_instances_and_clusters.sql | 17 +++ ...e_configured_to_copy_tags_to_snapshots.sql | 17 +++ ...should_be_configured_with_multiple_azs.sql | 17 +++ .../instances_should_be_deployed_in_a_vpc.sql | 17 +++ ...hould_have_deletion_protection_enabled.sql | 17 +++ ...should_have_ecnryption_at_rest_enabled.sql | 17 +++ ...nstances_should_prohibit_public_access.sql | 17 +++ .../rds/rds_cluster_default_admin_check.sql | 21 ++++ .../rds/rds_cluster_encrypted_at_rest.sql | 21 ++++ ...cluster_event_notifications_configured.sql | 25 ++++ .../rds/rds_instance_default_admin_check.sql | 21 ++++ ...nstance_event_notifications_configured.sql | 27 ++++ .../rds_pg_event_notifications_configured.sql | 24 ++++ .../rds_sg_event_notifications_configured.sql | 25 ++++ .../rds/rds_snapshots_public_prohibited.sql | 40 ++++++ .../redshift/redshift_cluster_kms_enabled.sql | 20 +++ .../redshift/redshift_default_admin_check.sql | 20 +++ .../redshift_default_db_name_check.sql | 20 +++ .../s3/s3_bucket_default_lock_enabled.sql | 26 ++++ ..._bucket_level_public_access_prohibited.sql | 27 ++++ .../macros/s3/s3_bucket_logging_enabled.sql | 23 ++++ .../s3/s3_event_notifications_enabled.sql | 25 ++++ .../macros/s3/s3_lifecycle_policy_check.sql | 25 ++++ .../s3/s3_version_lifecycle_policy_check.sql | 30 +++++ ...sagemaker_notebook_instance_inside_vpc.sql | 19 +++ ...er_notebook_instance_root_access_check.sql | 19 +++ ...unctions_state_machine_logging_enabled.sql | 22 ++++ .../macros/waf/waf_global_rule_not_empty.sql | 23 ++++ .../waf/waf_global_rulegroup_not_empty.sql | 22 ++++ .../waf/waf_global_webacl_not_empty.sql | 22 ++++ .../waf/waf_regional_rule_not_empty.sql | 23 ++++ .../waf/waf_regional_rulegroup_not_empty.sql | 22 ++++ .../waf/waf_regional_webacl_not_empty.sql | 21 ++++ .../aws/macros/waf/wafv2_webacl_not_empty.sql | 21 ++++ 120 files changed, 2882 insertions(+), 16 deletions(-) diff --git a/transformations/aws/compliance-premium/models/aws_compliance__foundational_security.sql b/transformations/aws/compliance-premium/models/aws_compliance__foundational_security.sql index f830d4820..04e712697 100644 --- a/transformations/aws/compliance-premium/models/aws_compliance__foundational_security.sql +++ b/transformations/aws/compliance-premium/models/aws_compliance__foundational_security.sql @@ -1,4 +1,4 @@ -{{ config(enabled=block_bigquery() and block_postgres()) }} +{{ config(enabled=block_bigquery()) }} with aggregated as ( @@ -390,7 +390,7 @@ with union ({{ security_account_information_provided('foundational_security','account.1') }}) union - ({{ security_groups_not_associated('foundational_security','ec2.22') }}) + ({{ security_groups_not_associated('foundational_security','ec2.22') }}) union ({{ security_groups_with_access_to_unauthorized_ports('foundational_security','ec2.18') }}) union diff --git a/transformations/aws/macros/account/security_account_information_provided.sql b/transformations/aws/macros/account/security_account_information_provided.sql index 36696955b..ce980fc00 100644 --- a/transformations/aws/macros/account/security_account_information_provided.sql +++ b/transformations/aws/macros/account/security_account_information_provided.sql @@ -28,6 +28,7 @@ select '{{check_id}}' as check_id, 'Security contact information should be provided for an AWS account' as title, aws_iam_accounts.account_id, + aws_iam_accounts.account_id as resource_id, case when alternate_contact_type is null then 'fail' diff --git a/transformations/aws/macros/acm/rsa_certificate_key_length_should_be_more_than_2048_bits.sql b/transformations/aws/macros/acm/rsa_certificate_key_length_should_be_more_than_2048_bits.sql index 450079a80..f7ddd30bd 100644 --- a/transformations/aws/macros/acm/rsa_certificate_key_length_should_be_more_than_2048_bits.sql +++ b/transformations/aws/macros/acm/rsa_certificate_key_length_should_be_more_than_2048_bits.sql @@ -1,4 +1,26 @@ {% macro rsa_certificate_key_length_should_be_more_than_2048_bits(framework, check_id) %} + {{ return(adapter.dispatch('rsa_certificate_key_length_should_be_more_than_2048_bits')(framework, check_id)) }} +{% endmacro %} + +{% macro default__rsa_certificate_key_length_should_be_more_than_2048_bits(framework, check_id) %}{% endmacro %} + +{% macro postgres__rsa_certificate_key_length_should_be_more_than_2048_bits(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'rsa certificate key length is less than 2048 bits' as title, + account_id, + arn AS resource_id, + CASE + WHEN key_algorithm IN ('RSA-1024', 'RSA 1024', 'RSA_1024') + THEN 'fail' + ELSE 'pass' + END AS status +FROM aws_acm_certificates +WHERE left(key_algorithm, 3) = 'RSA' +{% endmacro %} + +{% macro snowflake__rsa_certificate_key_length_should_be_more_than_2048_bits(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/apigateway/api_gw_stage_should_have_xray_tracing_enabled.sql b/transformations/aws/macros/apigateway/api_gw_stage_should_have_xray_tracing_enabled.sql index 5bac320d3..4a555254e 100644 --- a/transformations/aws/macros/apigateway/api_gw_stage_should_have_xray_tracing_enabled.sql +++ b/transformations/aws/macros/apigateway/api_gw_stage_should_have_xray_tracing_enabled.sql @@ -1,4 +1,25 @@ {% macro api_gw_stage_should_have_xray_tracing_enabled(framework, check_id) %} + {{ return(adapter.dispatch('api_gw_stage_should_have_xray_tracing_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__api_gw_stage_should_have_xray_tracing_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__api_gw_stage_should_have_xray_tracing_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'API Gateway REST API stages should have AWS X-Ray tracing enabled' as title, + account_id, + arn as resource_id, + CASE + WHEN tracing_enabled = true THEN 'pass' + ELSE 'fail' + END as status +FROM + aws_apigateway_rest_api_stages +{% endmacro %} + +{% macro snowflake__api_gw_stage_should_have_xray_tracing_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/apigateway/api_gw_stage_should_use_ssl.sql b/transformations/aws/macros/apigateway/api_gw_stage_should_use_ssl.sql index b0418d429..6c1ca3256 100644 --- a/transformations/aws/macros/apigateway/api_gw_stage_should_use_ssl.sql +++ b/transformations/aws/macros/apigateway/api_gw_stage_should_use_ssl.sql @@ -1,4 +1,25 @@ {% macro api_gw_stage_should_use_ssl(framework, check_id) %} + {{ return(adapter.dispatch('api_gw_stage_should_use_ssl')(framework, check_id)) }} +{% endmacro %} + +{% macro default__api_gw_stage_should_use_ssl(framework, check_id) %}{% endmacro %} + +{% macro postgres__api_gw_stage_should_use_ssl(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'API Gateway REST API stages should be configured to use SSL certificates for backend authentication' as title, + account_id, + arn as resource_id, + CASE + WHEN client_certificate_id is not null THEN 'pass' + ELSE 'fail' + END as status + +from aws_apigateway_rest_api_stages +{% endmacro %} + +{% macro snowflake__api_gw_stage_should_use_ssl(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/appsync/appsync_should_have_logging_turned_on.sql b/transformations/aws/macros/appsync/appsync_should_have_logging_turned_on.sql index 23a5f0238..07b847fb1 100644 --- a/transformations/aws/macros/appsync/appsync_should_have_logging_turned_on.sql +++ b/transformations/aws/macros/appsync/appsync_should_have_logging_turned_on.sql @@ -1,4 +1,26 @@ {% macro appsync_should_have_logging_turned_on(framework, check_id) %} + {{ return(adapter.dispatch('appsync_should_have_logging_turned_on')(framework, check_id)) }} +{% endmacro %} + +{% macro default__appsync_should_have_logging_turned_on(framework, check_id) %}{% endmacro %} + +{% macro postgres__appsync_should_have_logging_turned_on(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'AWS AppSync should have request-level and field-level logging turned on' as title, + account_id, + arn as resource_id, + CASE + WHEN (log_config ->> 'cloudWatchLogsRoleArn' IS NULL OR log_config ->> 'cloudWatchLogsRoleArn' = '') + OR + log_config ->> 'fieldLogLevel' = 'NONE' THEN 'fail' + ELSE 'pass' + END AS status +FROM aws_appsync_graphql_apis +{% endmacro %} + +{% macro snowflake__appsync_should_have_logging_turned_on(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/athena/athena_workgroup_encrypted_at_rest.sql b/transformations/aws/macros/athena/athena_workgroup_encrypted_at_rest.sql index 39956a99b..862a4d264 100644 --- a/transformations/aws/macros/athena/athena_workgroup_encrypted_at_rest.sql +++ b/transformations/aws/macros/athena/athena_workgroup_encrypted_at_rest.sql @@ -1,4 +1,23 @@ {% macro athena_workgroup_encrypted_at_rest(framework, check_id) %} + {{ return(adapter.dispatch('athena_workgroup_encrypted_at_rest')(framework, check_id)) }} +{% endmacro %} + +{% macro default__athena_workgroup_encrypted_at_rest(framework, check_id) %}{% endmacro %} + +{% macro postgres__athena_workgroup_encrypted_at_rest(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Athena workgroups should be encrypted at rest' AS "title", + account_id, + arn as resource_id, + case + WHEN CONFIGURATION -> 'ResultConfiguration' ->> 'EncryptionConfiguration' IS NULL THEN 'fail' + else 'pass' end as status +from aws_athena_work_groups +{% endmacro %} + +{% macro snowflake__athena_workgroup_encrypted_at_rest(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/autoscaling/autoscaling_group_elb_healthcheck_required.sql b/transformations/aws/macros/autoscaling/autoscaling_group_elb_healthcheck_required.sql index 0ed3e9b9b..68c6e65bb 100644 --- a/transformations/aws/macros/autoscaling/autoscaling_group_elb_healthcheck_required.sql +++ b/transformations/aws/macros/autoscaling/autoscaling_group_elb_healthcheck_required.sql @@ -1,4 +1,27 @@ {% macro autoscaling_group_elb_healthcheck_required(framework, check_id) %} + {{ return(adapter.dispatch('autoscaling_group_elb_healthcheck_required')(framework, check_id)) }} +{% endmacro %} + +{% macro default__autoscaling_group_elb_healthcheck_required(framework, check_id) %}{% endmacro %} + +{% macro postgres__autoscaling_group_elb_healthcheck_required(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Auto Scaling groups associated with a Classic Load Balancer should use load balancer health checks' AS "title", + account_id, + arn AS resource_id, + case + when array_length(load_balancer_names, 1) = 0 and array_length(target_group_arns, 1) = 0 then 'fail' + when health_check_type not like '%ELB%' then 'fail' + else 'pass' + END + AS status +FROM + aws_autoscaling_groups +{% endmacro %} + +{% macro snowflake__autoscaling_group_elb_healthcheck_required(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/autoscaling/autoscaling_launch_config_hop_limit.sql b/transformations/aws/macros/autoscaling/autoscaling_launch_config_hop_limit.sql index 0370768a7..d89209f27 100644 --- a/transformations/aws/macros/autoscaling/autoscaling_launch_config_hop_limit.sql +++ b/transformations/aws/macros/autoscaling/autoscaling_launch_config_hop_limit.sql @@ -1,4 +1,26 @@ {% macro autoscaling_launch_config_hop_limit(framework, check_id) %} + {{ return(adapter.dispatch('autoscaling_launch_config_hop_limit')(framework, check_id)) }} +{% endmacro %} + +{% macro default__autoscaling_launch_config_hop_limit(framework, check_id) %}{% endmacro %} + +{% macro postgres__autoscaling_launch_config_hop_limit(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Auto Scaling group launch configuration should not have a metadata response hop limit greater than 1' AS "title", + account_id, + arn AS resource_id, + case + when (METADATA_OPTIONS ->> 'HttpPutResponseHopLimit')::integer > 1 then 'fail' + else 'pass' + END + AS status +FROM + aws_autoscaling_launch_configurations +{% endmacro %} + +{% macro snowflake__autoscaling_launch_config_hop_limit(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/autoscaling/autoscaling_launch_config_public_ip_disabled.sql b/transformations/aws/macros/autoscaling/autoscaling_launch_config_public_ip_disabled.sql index 28b17d7ab..02ab23045 100644 --- a/transformations/aws/macros/autoscaling/autoscaling_launch_config_public_ip_disabled.sql +++ b/transformations/aws/macros/autoscaling/autoscaling_launch_config_public_ip_disabled.sql @@ -1,4 +1,26 @@ {% macro autoscaling_launch_config_public_ip_disabled(framework, check_id) %} + {{ return(adapter.dispatch('autoscaling_launch_config_public_ip_disabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__autoscaling_launch_config_public_ip_disabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__autoscaling_launch_config_public_ip_disabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Amazon EC2 instances launched using Auto Scaling group launch configurations should not have Public IP addresses' AS "title", + account_id, + arn AS resource_id, + case + when associate_public_ip_address = true then 'fail' + else 'pass' + END + AS status +FROM + aws_autoscaling_launch_configurations +{% endmacro %} + +{% macro snowflake__autoscaling_launch_config_public_ip_disabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/autoscaling/autoscaling_launch_template.sql b/transformations/aws/macros/autoscaling/autoscaling_launch_template.sql index 5fef73163..0a469d8d5 100644 --- a/transformations/aws/macros/autoscaling/autoscaling_launch_template.sql +++ b/transformations/aws/macros/autoscaling/autoscaling_launch_template.sql @@ -1,4 +1,26 @@ {% macro autoscaling_launch_template(framework, check_id) %} + {{ return(adapter.dispatch('autoscaling_launch_template')(framework, check_id)) }} +{% endmacro %} + +{% macro default__autoscaling_launch_template(framework, check_id) %}{% endmacro %} + +{% macro postgres__autoscaling_launch_template(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Amazon EC2 Auto Scaling groups should use Amazon EC2 launch templates' AS "title", + account_id, + arn AS resource_id, + case + when (LAUNCH_TEMPLATE)::Text is null then 'fail' + else 'pass' + END + AS status +FROM + aws_autoscaling_groups +{% endmacro %} + +{% macro snowflake__autoscaling_launch_template(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/autoscaling/autoscaling_launchconfig_requires_imdsv2.sql b/transformations/aws/macros/autoscaling/autoscaling_launchconfig_requires_imdsv2.sql index 9f4c05d8f..2c014fa8c 100644 --- a/transformations/aws/macros/autoscaling/autoscaling_launchconfig_requires_imdsv2.sql +++ b/transformations/aws/macros/autoscaling/autoscaling_launchconfig_requires_imdsv2.sql @@ -1,4 +1,26 @@ {% macro autoscaling_launchconfig_requires_imdsv2(framework, check_id) %} + {{ return(adapter.dispatch('autoscaling_launchconfig_requires_imdsv2')(framework, check_id)) }} +{% endmacro %} + +{% macro default__autoscaling_launchconfig_requires_imdsv2(framework, check_id) %}{% endmacro %} + +{% macro postgres__autoscaling_launchconfig_requires_imdsv2(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Auto Scaling group launch configurations should configure EC2 instances to require Instance Metadata Service Version 2' AS "title", + account_id, + arn AS resource_id, + case + when METADATA_OPTIONS ->> 'HttpTokens' = 'required' then 'pass' + else 'fail' + END + AS status +FROM + aws_autoscaling_launch_configurations +{% endmacro %} + +{% macro snowflake__autoscaling_launchconfig_requires_imdsv2(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/autoscaling/autoscaling_multiple_az.sql b/transformations/aws/macros/autoscaling/autoscaling_multiple_az.sql index 9033cc35e..eccefcc03 100644 --- a/transformations/aws/macros/autoscaling/autoscaling_multiple_az.sql +++ b/transformations/aws/macros/autoscaling/autoscaling_multiple_az.sql @@ -1,4 +1,26 @@ {% macro autoscaling_multiple_az(framework, check_id) %} + {{ return(adapter.dispatch('autoscaling_multiple_az')(framework, check_id)) }} +{% endmacro %} + +{% macro default__autoscaling_multiple_az(framework, check_id) %}{% endmacro %} + +{% macro postgres__autoscaling_multiple_az(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Amazon EC2 Auto Scaling group should cover multiple Availability Zones' AS "title", + account_id, + arn AS resource_id, + case + when array_length(availability_zones, 1) > 1 then 'pass' + else 'fail' + END + AS status +FROM + aws_autoscaling_groups +{% endmacro %} + +{% macro snowflake__autoscaling_multiple_az(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/autoscaling/autoscaling_multiple_instance_types.sql b/transformations/aws/macros/autoscaling/autoscaling_multiple_instance_types.sql index 52d14cc39..2b915a9ad 100644 --- a/transformations/aws/macros/autoscaling/autoscaling_multiple_instance_types.sql +++ b/transformations/aws/macros/autoscaling/autoscaling_multiple_instance_types.sql @@ -1,4 +1,33 @@ {% macro autoscaling_multiple_instance_types(framework, check_id) %} + {{ return(adapter.dispatch('autoscaling_multiple_instance_types')(framework, check_id)) }} +{% endmacro %} + +{% macro default__autoscaling_multiple_instance_types(framework, check_id) %}{% endmacro %} + +{% macro postgres__autoscaling_multiple_instance_types(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Auto Scaling groups should use multiple instance types in multiple Availability Zones' AS "title", + aag.account_id, + ditc.arn AS resource_id, + ditc.status +FROM aws_autoscaling_groups as aag +JOIN ( + SELECT + arn, + CASE + WHEN COUNT(DISTINCT instance ->> 'InstanceType') > 1 THEN 'pass' + ELSE 'fail' + END AS status + FROM + aws_autoscaling_groups AS aag, + JSONB_ARRAY_ELEMENTS(aag.INSTANCES) as instance + GROUP BY arn +) AS ditc ON aag.arn = ditc.arn +{% endmacro %} + +{% macro snowflake__autoscaling_multiple_instance_types(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/cloudformation/cloudformation_stack_notification_check.sql b/transformations/aws/macros/cloudformation/cloudformation_stack_notification_check.sql index 110a4e145..aeced9543 100644 --- a/transformations/aws/macros/cloudformation/cloudformation_stack_notification_check.sql +++ b/transformations/aws/macros/cloudformation/cloudformation_stack_notification_check.sql @@ -1,4 +1,26 @@ {% macro cloudformation_stack_notification_check(framework, check_id) %} + {{ return(adapter.dispatch('cloudformation_stack_notification_check')(framework, check_id)) }} +{% endmacro %} + +{% macro default__cloudformation_stack_notification_check(framework, check_id) %}{% endmacro %} + +{% macro postgres__cloudformation_stack_notification_check(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'CloudFormation stacks should be integrated with Simple Notification Service (SNS)' AS "title", + account_id, + arn AS resource_id, + case + when array_length(notification_arns, 1) > 0 then 'pass' + else 'fail' + END + AS status +FROM + aws_cloudformation_stacks +{% endmacro %} + +{% macro snowflake__cloudformation_stack_notification_check(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/cloudfront/distribution_should_encrypt_traffic_to_custom_origins.sql b/transformations/aws/macros/cloudfront/distribution_should_encrypt_traffic_to_custom_origins.sql index 7d0da39f6..6b4cfb2c2 100644 --- a/transformations/aws/macros/cloudfront/distribution_should_encrypt_traffic_to_custom_origins.sql +++ b/transformations/aws/macros/cloudfront/distribution_should_encrypt_traffic_to_custom_origins.sql @@ -1,4 +1,53 @@ {% macro distribution_should_encrypt_traffic_to_custom_origins(framework, check_id) %} + {{ return(adapter.dispatch('distribution_should_encrypt_traffic_to_custom_origins')(framework, check_id)) }} +{% endmacro %} + +{% macro default__distribution_should_encrypt_traffic_to_custom_origins(framework, check_id) %}{% endmacro %} + +{% macro postgres__distribution_should_encrypt_traffic_to_custom_origins(framework, check_id) %} +with origins as ( + select distinct + arn, + f -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' as policy + from + aws_cloudfront_distributions d, + JSONB_ARRAY_ELEMENTS(distribution_config -> 'Origins' -> 'Items') as f + WHERE + f -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' = 'http-only' + or f -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' = 'match-viewer' + +), +cache_behaviors as ( + select distinct + arn + from + aws_cloudfront_distributions d, + JSONB_ARRAY_ELEMENTS(COALESCE(distribution_config -> 'CacheBehaviors' -> 'Items', '{}')) as f + where + f ->> 'ViewerProtocolPolicy' = 'allow-all' +) +select distinct + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'CloudFront distributions should encrypt traffic to custom origins' as title, + d.account_id, + d.arn as resource_id, + CASE + WHEN o.policy = 'http-only' THEN 'fail' + WHEN o.policy = 'match-viewer' and (cb.arn is not null + or + distribution_config -> 'DefaultCacheBehavior' ->> 'ViewerProtocolPolicy' = 'allow-all') + THEN 'fail' + ELSE 'pass' + END as status + +from + aws_cloudfront_distributions d + LEFT JOIN origins as o on d.arn = o.arn + LEFT JOIN cache_behaviors as cb on d.arn = cb.arn +{% endmacro %} + +{% macro snowflake__distribution_should_encrypt_traffic_to_custom_origins(framework, check_id) %} with origins as ( select distinct arn, diff --git a/transformations/aws/macros/cloudfront/distribution_should_not_point_to_non_existent_s3_origins.sql b/transformations/aws/macros/cloudfront/distribution_should_not_point_to_non_existent_s3_origins.sql index 71b2263c3..6dc8c3b08 100644 --- a/transformations/aws/macros/cloudfront/distribution_should_not_point_to_non_existent_s3_origins.sql +++ b/transformations/aws/macros/cloudfront/distribution_should_not_point_to_non_existent_s3_origins.sql @@ -1,5 +1,49 @@ {% macro distribution_should_not_point_to_non_existent_s3_origins(framework, check_id) %} -wITH s3_origins AS ( + {{ return(adapter.dispatch('distribution_should_not_point_to_non_existent_s3_origins')(framework, check_id)) }} +{% endmacro %} + +{% macro default__distribution_should_not_point_to_non_existent_s3_origins(framework, check_id) %}{% endmacro %} + +{% macro postgres__distribution_should_not_point_to_non_existent_s3_origins(framework, check_id) %} +WITH s3_origins AS ( + SELECT DISTINCT + arn, + o ->> 'DomainName' AS s3_domain_name + FROM + aws_cloudfront_distributions, + JSONB_ARRAY_ELEMENTS(COALESCE(distribution_config -> 'Origins' -> 'Items', '{}')) as o + WHERE + (o ->> 'S3OriginConfig' IS NOT NULL OR o ->> 'S3OriginConfig' <> 'null') + AND o ->> 'DomainName' LIKE '%.s3.%' +), +s3_origins_no_bucket AS ( +SELECT DISTINCT + s.arn +FROM + s3_origins s +LEFT JOIN aws_s3_buckets b ON SPLIT_PART(s3_domain_name, '.', 1) = b.name +WHERE b.name is null + + ) +SELECT DISTINCT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'CloudFront distributions should not point to non-existent S3 origins' as title, + d.account_id, + d.arn as resouce_id, + CASE + WHEN o.arn is null THEN 'pass' + ELSE 'fail' + END as status + +FROM aws_cloudfront_distributions d + LEFT JOIN s3_origins_no_bucket o + ON d.arn = o.arn + +{% endmacro %} + +{% macro snowflake__distribution_should_not_point_to_non_existent_s3_origins(framework, check_id) %} +WITH s3_origins AS ( SELECT DISTINCT arn, o.value:DomainName AS s3_domain_name diff --git a/transformations/aws/macros/cloudfront/distribution_should_not_use_depricated_ssl_protocols.sql b/transformations/aws/macros/cloudfront/distribution_should_not_use_depricated_ssl_protocols.sql index 762bafe55..337d84078 100644 --- a/transformations/aws/macros/cloudfront/distribution_should_not_use_depricated_ssl_protocols.sql +++ b/transformations/aws/macros/cloudfront/distribution_should_not_use_depricated_ssl_protocols.sql @@ -1,5 +1,39 @@ {% macro distribution_should_not_use_depricated_ssl_protocols(framework, check_id) %} -wITH origins_with_sslv3 AS ( + {{ return(adapter.dispatch('distribution_should_not_use_depricated_ssl_protocols')(framework, check_id)) }} +{% endmacro %} + +{% macro default__distribution_should_not_use_depricated_ssl_protocols(framework, check_id) %}{% endmacro %} + +{% macro postgres__distribution_should_not_use_depricated_ssl_protocols(framework, check_id) %} +WITH origins_with_sslv3 AS ( +SELECT DISTINCT + arn, + o ->> Id AS origin_id +FROM + aws_cloudfront_distributions, + JSONB_ARRAY_ELEMENTS(COALESCE(distribution_config -> 'Origins' -> 'Items', '{}')) as o +WHERE + o -> 'CustomOriginConfig' -> 'OriginSslProtocols' -> 'Items' ? 'SSLv3' +) + +SELECT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'CloudFront distributions should not use deprecated SSL protocols between edge locations and custom origins' as title, + d.arn as resource_id, + d.account_id, + CASE + WHEN o.arn is null THEN 'pass' + ELSE 'fail' + END as status +FROM + aws_cloudfront_distributions d + LEFT JOIN origins_with_sslv3 o + ON d.arn = o.arn +{% endmacro %} + +{% macro snowflake__distribution_should_not_use_depricated_ssl_protocols(framework, check_id) %} +WITH origins_with_sslv3 AS ( SELECT DISTINCT arn, o.value:Id AS origin_id diff --git a/transformations/aws/macros/cloudfront/distribution_should_use_origin_access_control.sql b/transformations/aws/macros/cloudfront/distribution_should_use_origin_access_control.sql index 2f8ddb735..33ede0e86 100644 --- a/transformations/aws/macros/cloudfront/distribution_should_use_origin_access_control.sql +++ b/transformations/aws/macros/cloudfront/distribution_should_use_origin_access_control.sql @@ -1,4 +1,49 @@ {% macro distribution_should_use_origin_access_control(framework, check_id) %} + {{ return(adapter.dispatch('distribution_should_use_origin_access_control')(framework, check_id)) }} +{% endmacro %} + +{% macro default__distribution_should_use_origin_access_control(framework, check_id) %}{% endmacro %} + +{% macro postgres__distribution_should_use_origin_access_control(framework, check_id) %} +WITH s3_origins AS ( + SELECT DISTINCT + arn, + o ->> 'DomainName' AS s3_domain_name, + o ->> 'OriginAccessControlId' AS origin_access_control_id + FROM + aws_cloudfront_distributions, + JSONB_ARRAY_ELEMENTS(COALESCE(distribution_config -> 'Origins' -> 'Items', '{}')) as o + WHERE + o ->> 'S3OriginConfig' IS NOT NULL + AND o ->> 'DomainName' LIKE '%.s3.%' +), +s3_origins_with_buckets AS ( +SELECT DISTINCT + s.arn, + s.origin_access_control_id +FROM + s3_origins s +INNER JOIN aws_s3_buckets b ON SPLIT_PART(s3_domain_name, '.', 1) = b.name + ) + +SELECT DISTINCT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'CloudFront distributions should use origin access control' as title, + d.account_id, + d.arn as resouce_id, + CASE + WHEN o.arn is not null + and (o.origin_access_control_id is null + or o.origin_access_control_id = '') THEN 'fail' + ELSE 'pass' + END as status + +FROM aws_cloudfront_distributions as d +LEFT JOIN s3_origins_with_buckets as o ON d.arn = o.arn +{% endmacro %} + +{% macro snowflake__distribution_should_use_origin_access_control(framework, check_id) %} WITH s3_origins AS ( SELECT DISTINCT arn, diff --git a/transformations/aws/macros/cloudfront/distribution_should_use_sni.sql b/transformations/aws/macros/cloudfront/distribution_should_use_sni.sql index 07afea4ec..e4ad5e64a 100644 --- a/transformations/aws/macros/cloudfront/distribution_should_use_sni.sql +++ b/transformations/aws/macros/cloudfront/distribution_should_use_sni.sql @@ -1,4 +1,25 @@ {% macro distribution_should_use_sni(framework, check_id) %} + {{ return(adapter.dispatch('distribution_should_use_sni')(framework, check_id)) }} +{% endmacro %} + +{% macro default__distribution_should_use_sni(framework, check_id) %}{% endmacro %} + +{% macro postgres__distribution_should_use_sni(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'CloudFront distributions should use SNI to serve HTTPS requests' as title, + account_id, + arn as resource_id, + CASE + WHEN distribution_config -> 'ViewerCertificate' ->> 'SSLSupportMethod' <> 'sni-only' + THEN 'fail' + ELSE 'pass' + END as status +from aws_cloudfront_distributions +{% endmacro %} + +{% macro snowflake__distribution_should_use_sni(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/cloudfront/distribution_should_use_ssl_tls_certificates.sql b/transformations/aws/macros/cloudfront/distribution_should_use_ssl_tls_certificates.sql index 44fdbefc2..1bb14c36a 100644 --- a/transformations/aws/macros/cloudfront/distribution_should_use_ssl_tls_certificates.sql +++ b/transformations/aws/macros/cloudfront/distribution_should_use_ssl_tls_certificates.sql @@ -1,4 +1,29 @@ {% macro distribution_should_use_ssl_tls_certificates(framework, check_id) %} + {{ return(adapter.dispatch('distribution_should_use_ssl_tls_certificates')(framework, check_id)) }} +{% endmacro %} + +{% macro default__distribution_should_use_ssl_tls_certificates(framework, check_id) %}{% endmacro %} + +{% macro postgres__distribution_should_use_ssl_tls_certificates(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'CloudFront distributions should use custom SSL/TLS certificates' as title, + account_id, + arn as resource_id, + CASE + WHEN (distribution_config -> 'ViewerCertificate' ->> 'ACMCertificateArn' is null + AND + distribution_config -> 'ViewerCertificate' ->> 'IAMCertificateId' is null + ) + OR (distribution_config -> 'ViewerCertificate' ->> 'CloudFrontDefaultCertificate')::boolean = true + THEN 'fail' + ELSE 'pass' + END as status +from aws_cloudfront_distributions +{% endmacro %} + +{% macro snowflake__distribution_should_use_ssl_tls_certificates(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/cloudfront/origin_access_identity_enabled.sql b/transformations/aws/macros/cloudfront/origin_access_identity_enabled.sql index 2edb091a2..a7af4c17c 100644 --- a/transformations/aws/macros/cloudfront/origin_access_identity_enabled.sql +++ b/transformations/aws/macros/cloudfront/origin_access_identity_enabled.sql @@ -1,4 +1,25 @@ {% macro origin_access_identity_enabled(framework, check_id) %} + {{ return(adapter.dispatch('origin_access_identity_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__origin_access_identity_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__origin_access_identity_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'CloudFront distributions should have origin access identity enabled' as title, + account_id, + arn as resource_id, + CASE + WHEN o ->> 'DomainName' LIKE '%s3.amazonaws.com' AND o -> 'S3OriginConfig' ->> 'OriginAccessIdentity' = '' THEN 'fail' + ELSE 'pass' + END AS status +from aws_cloudfront_distributions, +JSONB_ARRAY_ELEMENTS(distribution_config->'Origins'->'Items') as o +{% endmacro %} + +{% macro snowflake__origin_access_identity_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/cloudtrail/logs_file_validation_enabled.sql b/transformations/aws/macros/cloudtrail/logs_file_validation_enabled.sql index 6691feba7..6c1019538 100644 --- a/transformations/aws/macros/cloudtrail/logs_file_validation_enabled.sql +++ b/transformations/aws/macros/cloudtrail/logs_file_validation_enabled.sql @@ -1,4 +1,24 @@ {% macro logs_file_validation_enabled(framework, check_id) %} + {{ return(adapter.dispatch('logs_file_validation_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__logs_file_validation_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__logs_file_validation_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Ensure CloudTrail log file validation is enabled' as title, + account_id, + arn as resource_id, + case + when log_file_validation_enabled = false then 'fail' + else 'pass' + end as status +from aws_cloudtrail_trails +{% endmacro %} + +{% macro snowflake__logs_file_validation_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/codebuild/project_environment_has_logging_aws_configuration.sql b/transformations/aws/macros/codebuild/project_environment_has_logging_aws_configuration.sql index 9b5fe35c5..18b86bcca 100644 --- a/transformations/aws/macros/codebuild/project_environment_has_logging_aws_configuration.sql +++ b/transformations/aws/macros/codebuild/project_environment_has_logging_aws_configuration.sql @@ -1,4 +1,26 @@ {% macro project_environment_has_logging_aws_configuration(framework, check_id) %} + {{ return(adapter.dispatch('project_environment_has_logging_aws_configuration')(framework, check_id)) }} +{% endmacro %} + +{% macro default__project_environment_has_logging_aws_configuration(framework, check_id) %}{% endmacro %} + +{% macro postgres__project_environment_has_logging_aws_configuration(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'CodeBuild project environments should have a logging AWS Configuration' as title, + account_id, + arn as resource_id, + CASE + WHEN (logs_config -> 'S3Logs' ->> 'status' = 'ENABLED') + or (logs_config -> 'CloudWatchLogs' ->>'status' = 'ENABLED') + then 'pass' + ELSE 'fail' + END as status +from aws_codebuild_projects +{% endmacro %} + +{% macro snowflake__project_environment_has_logging_aws_configuration(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/codebuild/project_environment_should_not_have_privileged_mode.sql b/transformations/aws/macros/codebuild/project_environment_should_not_have_privileged_mode.sql index 71e5a95a7..138cd7266 100644 --- a/transformations/aws/macros/codebuild/project_environment_should_not_have_privileged_mode.sql +++ b/transformations/aws/macros/codebuild/project_environment_should_not_have_privileged_mode.sql @@ -1,4 +1,24 @@ {% macro project_environment_should_not_have_privileged_mode(framework, check_id) %} + {{ return(adapter.dispatch('project_environment_should_not_have_privileged_mode')(framework, check_id)) }} +{% endmacro %} + +{% macro default__project_environment_should_not_have_privileged_mode(framework, check_id) %}{% endmacro %} + +{% macro postgres__project_environment_should_not_have_privileged_mode(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'CodeBuild project environments should not have privileged mode enabled' as title, + account_id, + arn as resource_id, + CASE + WHEN (logs_config -> 'environment' ->> 'PrivilegedMode')::boolean then 'fail' + ELSE 'pass' + END as status +from aws_codebuild_projects +{% endmacro %} + +{% macro snowflake__project_environment_should_not_have_privileged_mode(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/codebuild/s3_logs_encrypted.sql b/transformations/aws/macros/codebuild/s3_logs_encrypted.sql index db0dcd78d..c5d45e43f 100644 --- a/transformations/aws/macros/codebuild/s3_logs_encrypted.sql +++ b/transformations/aws/macros/codebuild/s3_logs_encrypted.sql @@ -1,4 +1,24 @@ {% macro s3_logs_encrypted(framework, check_id) %} + {{ return(adapter.dispatch('s3_logs_encrypted')(framework, check_id)) }} +{% endmacro %} + +{% macro default__s3_logs_encrypted(framework, check_id) %}{% endmacro %} + +{% macro postgres__s3_logs_encrypted(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'CodeBuild S3 logs should be encrypted' as title, + account_id, + arn as resource_id, + CASE + WHEN (logs_config -> 'S3Logs' ->> 'encryptionDisabled')::boolean then 'fail' + ELSE 'pass' + END as status +from aws_codebuild_projects +{% endmacro %} + +{% macro snowflake__s3_logs_encrypted(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/documentdb/clusters_should_be_encrypted_at_rest.sql b/transformations/aws/macros/documentdb/clusters_should_be_encrypted_at_rest.sql index 98ca058eb..a2f7b3786 100644 --- a/transformations/aws/macros/documentdb/clusters_should_be_encrypted_at_rest.sql +++ b/transformations/aws/macros/documentdb/clusters_should_be_encrypted_at_rest.sql @@ -1,4 +1,24 @@ {% macro clusters_should_be_encrypted_at_rest(framework, check_id) %} + {{ return(adapter.dispatch('clusters_should_be_encrypted_at_rest')(framework, check_id)) }} +{% endmacro %} + +{% macro default__clusters_should_be_encrypted_at_rest(framework, check_id) %}{% endmacro %} + +{% macro postgres__clusters_should_be_encrypted_at_rest(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Amazon DocumentDB clusters should be encrypted at rest' as title, + account_id, + arn as resource_id, + CASE + WHEN storage_encrypted = false THEN 'fail' + ELSE 'pass' + END as status +FROM aws_docdb_clusters +{% endmacro %} + +{% macro snowflake__clusters_should_be_encrypted_at_rest(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/documentdb/clusters_should_have_7_days_backup_retention.sql b/transformations/aws/macros/documentdb/clusters_should_have_7_days_backup_retention.sql index fe43ca67f..763e97f8e 100644 --- a/transformations/aws/macros/documentdb/clusters_should_have_7_days_backup_retention.sql +++ b/transformations/aws/macros/documentdb/clusters_should_have_7_days_backup_retention.sql @@ -1,4 +1,24 @@ {% macro clusters_should_have_7_days_backup_retention(framework, check_id) %} + {{ return(adapter.dispatch('clusters_should_have_7_days_backup_retention')(framework, check_id)) }} +{% endmacro %} + +{% macro default__clusters_should_have_7_days_backup_retention(framework, check_id) %}{% endmacro %} + +{% macro postgres__clusters_should_have_7_days_backup_retention(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Amazon DocumentDB clusters should have an adequate backup retention period' as title, + account_id, + arn as resource_id, + CASE + WHEN backup_retention_period >= 7 THEN 'pass' + ELSE 'fail' + END as status +FROM aws_docdb_clusters +{% endmacro %} + +{% macro snowflake__clusters_should_have_7_days_backup_retention(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/ec2/both_vpn_channels_should_be_up.sql b/transformations/aws/macros/ec2/both_vpn_channels_should_be_up.sql index 098678722..8fb0e891c 100644 --- a/transformations/aws/macros/ec2/both_vpn_channels_should_be_up.sql +++ b/transformations/aws/macros/ec2/both_vpn_channels_should_be_up.sql @@ -1,5 +1,36 @@ {% macro both_vpn_channels_should_be_up(framework, check_id) %} -wITH TunnelStatus AS ( + {{ return(adapter.dispatch('both_vpn_channels_should_be_up')(framework, check_id)) }} +{% endmacro %} + +{% macro default__both_vpn_channels_should_be_up(framework, check_id) %}{% endmacro %} + +{% macro postgres__both_vpn_channels_should_be_up(framework, check_id) %} +WITH TunnelStatus AS ( + SELECT + distinct c.vpn_connection_id, + COUNT(CASE WHEN t ->> 'Status' = 'UP' THEN 1 END) OVER(PARTITION BY c.vpn_connection_id) as up_count + FROM + aws_ec2_vpn_connections c, + JSONB_ARRAY_ELEMENTS(vgw_telemetry) as t +) + +SELECT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Both VPN tunnels for an AWS Site-to-Site VPN connection should be up' as title, + c.account_id, + 'arn:aws:ec2:' || c.region || ':' || c.account_id || ':vpn-connection/' || c.vpn_connection_id AS resource_id, + CASE + WHEN t.up_count >= 2 THEN 'pass' + ELSE 'fail' + END as status +FROM + aws_ec2_vpn_connections c +LEFT JOIN TunnelStatus t ON c.vpn_connection_id = t.vpn_connection_id +{% endmacro %} + +{% macro snowflake__both_vpn_channels_should_be_up(framework, check_id) %} +WITH TunnelStatus AS ( SELECT distinct c.vpn_connection_id, COUNT_IF(t.value:Status::text = 'UP') OVER(PARTITION BY c.vpn_connection_id) as up_count diff --git a/transformations/aws/macros/ec2/launch_templates_should_not_assign_public_ip.sql b/transformations/aws/macros/ec2/launch_templates_should_not_assign_public_ip.sql index 28238c100..006b4b0f2 100644 --- a/transformations/aws/macros/ec2/launch_templates_should_not_assign_public_ip.sql +++ b/transformations/aws/macros/ec2/launch_templates_should_not_assign_public_ip.sql @@ -1,5 +1,42 @@ {% macro launch_templates_should_not_assign_public_ip(framework, check_id) %} -wITH FlattenedData AS ( + {{ return(adapter.dispatch('launch_templates_should_not_assign_public_ip')(framework, check_id)) }} +{% endmacro %} + +{% macro default__launch_templates_should_not_assign_public_ip(framework, check_id) %}{% endmacro %} + +{% macro postgres__launch_templates_should_not_assign_public_ip(framework, check_id) %} +WITH FlattenedData AS ( + SELECT + account_id, + arn, + flat_interfaces.value as interface + FROM + aws_ec2_launch_template_versions, + JSONB_ARRAY_ELEMENTS(launch_template_data->'networkInterfaceSet') as flat_interfaces + WHERE default_version +) + +SELECT + DISTINCT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Amazon EC2 launch templates should not assign public IPs to network interfaces' as title, + FlattenedData.account_id, + FlattenedData.arn as resource_id, + CASE + WHEN association ->> 'publicIp' is not null + OR (interface ->> 'associatePublicIpAddress')::BOOLEAN = TRUE THEN 'fail' + ELSE 'pass' + END as status +FROM + FlattenedData +LEFT JOIN + aws_ec2_network_interfaces + ON interface ->> 'networkInterfaceId' = aws_ec2_network_interfaces.network_interface_id +{% endmacro %} + +{% macro snowflake__launch_templates_should_not_assign_public_ip(framework, check_id) %} +WITH FlattenedData AS ( SELECT account_id, arn, diff --git a/transformations/aws/macros/ec2/network_acls_should_not_allow_ingress_for_ssh_rdp_ports.sql b/transformations/aws/macros/ec2/network_acls_should_not_allow_ingress_for_ssh_rdp_ports.sql index 135fd28d5..7e7ad245f 100644 --- a/transformations/aws/macros/ec2/network_acls_should_not_allow_ingress_for_ssh_rdp_ports.sql +++ b/transformations/aws/macros/ec2/network_acls_should_not_allow_ingress_for_ssh_rdp_ports.sql @@ -1,5 +1,48 @@ {% macro network_acls_should_not_allow_ingress_for_ssh_rdp_ports(framework, check_id) %} -wITH bad_entries as ( + {{ return(adapter.dispatch('network_acls_should_not_allow_ingress_for_ssh_rdp_ports')(framework, check_id)) }} +{% endmacro %} + +{% macro default__network_acls_should_not_allow_ingress_for_ssh_rdp_ports(framework, check_id) %}{% endmacro %} + +{% macro postgres__network_acls_should_not_allow_ingress_for_ssh_rdp_ports(framework, check_id) %} +WITH bad_entries as ( +SELECT + DISTINCT + arn +FROM + aws_ec2_network_acls, + JSONB_ARRAY_ELEMENTS(entries) as entry +WHERE + entry.value ->> 'Egress' = 'false' + AND entry.value ->> 'Protocol' = '6' + AND entry.value ->> 'RuleAction' = 'allow' + AND ( + (entry.value -> 'PortRange' ->> 'From')::INTEGER IN (22, 3389) + OR (entry.value -> 'PortRange' ->> 'To')::INTEGER IN (22, 3389) + ) + AND ( + entry.value ->> 'CidrBlock' = '0.0.0.0/0' + OR entry.value ->> 'Ipv6CidrBlock' = '::/0' +) +) +SELECT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Network ACLs should not allow ingress from 0.0.0.0/0 to port 22 or port 3389' as title, + a.account_id, + a.arn as resource_id, + CASE + WHEN b.arn is not null THEN 'fail' + ELSE 'pass' + END as status +FROM + aws_ec2_network_acls a +LEFT JOIN bad_entries b + ON a.arn = b.arn +{% endmacro %} + +{% macro snowflake__network_acls_should_not_allow_ingress_for_ssh_rdp_ports(framework, check_id) %} +WITH bad_entries as ( SELECT DISTINCT arn diff --git a/transformations/aws/macros/ec2/not_imdsv2_instances.sql b/transformations/aws/macros/ec2/not_imdsv2_instances.sql index 3547877b2..adf8cd2bb 100644 --- a/transformations/aws/macros/ec2/not_imdsv2_instances.sql +++ b/transformations/aws/macros/ec2/not_imdsv2_instances.sql @@ -1,4 +1,25 @@ {% macro not_imdsv2_instances(framework, check_id) %} + {{ return(adapter.dispatch('not_imdsv2_instances')(framework, check_id)) }} +{% endmacro %} + +{% macro default__not_imdsv2_instances(framework, check_id) %}{% endmacro %} + +{% macro postgres__not_imdsv2_instances(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'EC2 instances should use IMDSv2' as title, + account_id, + instance_id as resource_id, + case when + metadata_options ->> 'HttpTokens' is distinct from 'required' + then 'fail' + else 'pass' + end as status +from aws_ec2_instances +{% endmacro %} + +{% macro snowflake__not_imdsv2_instances(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/ec2/paravirtual_instances_should_not_be_used.sql b/transformations/aws/macros/ec2/paravirtual_instances_should_not_be_used.sql index 27887b2aa..ca2075374 100644 --- a/transformations/aws/macros/ec2/paravirtual_instances_should_not_be_used.sql +++ b/transformations/aws/macros/ec2/paravirtual_instances_should_not_be_used.sql @@ -1,4 +1,24 @@ {% macro paravirtual_instances_should_not_be_used(framework, check_id) %} + {{ return(adapter.dispatch('paravirtual_instances_should_not_be_used')(framework, check_id)) }} +{% endmacro %} + +{% macro default__paravirtual_instances_should_not_be_used(framework, check_id) %}{% endmacro %} + +{% macro postgres__paravirtual_instances_should_not_be_used(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Amazon EC2 paravirtual instance types should not be used' as title, + account_id, + arn as resource_id, + CASE + WHEN virtualization_type = 'paravirtual' THEN 'fail' + ELSE 'pass' + END as status +FROM aws_ec2_instances +{% endmacro %} + +{% macro snowflake__paravirtual_instances_should_not_be_used(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/ec2/security_groups_not_associated.sql b/transformations/aws/macros/ec2/security_groups_not_associated.sql index 8cbbcd803..3d03b3dfb 100644 --- a/transformations/aws/macros/ec2/security_groups_not_associated.sql +++ b/transformations/aws/macros/ec2/security_groups_not_associated.sql @@ -1,5 +1,36 @@ {% macro security_groups_not_associated(framework, check_id) %} -wITH used_security_groups AS ( + {{ return(adapter.dispatch('security_groups_not_associated')(framework, check_id)) }} +{% endmacro %} + +{% macro default__security_groups_not_associated(framework, check_id) %}{% endmacro %} + +{% macro postgres__security_groups_not_associated(framework, check_id) %} +WITH used_security_groups AS ( + -- Security groups associated with EC2 instances + SELECT sg ->> 'GroupId' as security_group_id + FROM aws_ec2_instances, + JSONB_ARRAY_ELEMENTS(security_groups) as sg + UNION + -- Security groups associated with network interfaces + SELECT sg ->> 'GroupId' as security_group_id + FROM aws_ec2_network_interfaces, + JSONB_ARRAY_ELEMENTS(groups) as sg +) +SELECT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Unused Amazon EC2 security groups should be removed' as title, + account_id, + arn as resource_id, +CASE +when group_id IN (SELECT DISTINCT security_group_id FROM used_security_groups) THEN 'pass' +ELSE 'fail' +END as status +FROM aws_ec2_security_groups +{% endmacro %} + +{% macro snowflake__security_groups_not_associated(framework, check_id) %} +WITH used_security_groups AS ( -- Security groups associated with EC2 instances SELECT sg.value:GroupId::text as security_group_id FROM aws_ec2_instances diff --git a/transformations/aws/macros/ec2/transit_gateways_should_not_auto_accept_vpc_attachments.sql b/transformations/aws/macros/ec2/transit_gateways_should_not_auto_accept_vpc_attachments.sql index 86f1584f2..0a42997f4 100644 --- a/transformations/aws/macros/ec2/transit_gateways_should_not_auto_accept_vpc_attachments.sql +++ b/transformations/aws/macros/ec2/transit_gateways_should_not_auto_accept_vpc_attachments.sql @@ -1,4 +1,24 @@ {% macro transit_gateways_should_not_auto_accept_vpc_attachments(framework, check_id) %} + {{ return(adapter.dispatch('transit_gateways_should_not_auto_accept_vpc_attachments')(framework, check_id)) }} +{% endmacro %} + +{% macro default__transit_gateways_should_not_auto_accept_vpc_attachments(framework, check_id) %}{% endmacro %} + +{% macro postgres__transit_gateways_should_not_auto_accept_vpc_attachments(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Amazon EC2 Transit Gateways should not automatically accept VPC attachment requests' as title, + account_id, + arn as resource_id, + CASE + WHEN options ->> 'AutoAcceptSharedAttachments' = 'enable' THEN 'fail' + ELSE 'pass' + END as status +FROM aws_ec2_transit_gateways +{% endmacro %} + +{% macro snowflake__transit_gateways_should_not_auto_accept_vpc_attachments(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/ecr/private_repositories_have_image_scanning_configured.sql b/transformations/aws/macros/ecr/private_repositories_have_image_scanning_configured.sql index 2423d3b13..241836ffd 100644 --- a/transformations/aws/macros/ecr/private_repositories_have_image_scanning_configured.sql +++ b/transformations/aws/macros/ecr/private_repositories_have_image_scanning_configured.sql @@ -1,4 +1,25 @@ {% macro private_repositories_have_image_scanning_configured(framework, check_id) %} + {{ return(adapter.dispatch('private_repositories_have_image_scanning_configured')(framework, check_id)) }} +{% endmacro %} + +{% macro default__private_repositories_have_image_scanning_configured(framework, check_id) %}{% endmacro %} + +{% macro postgres__private_repositories_have_image_scanning_configured(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'ECR private repositories should have image scanning configured' as title, + account_id, + arn as resource_id, + CASE + WHEN image_scanning_configuration ->> 'ScanOnPush' = 'false' THEN 'fail' + ELSE 'pass' + END as status + FROM + aws_ecr_repositories +{% endmacro %} + +{% macro snowflake__private_repositories_have_image_scanning_configured(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/ecr/private_repositories_have_tag_immutability_configured.sql b/transformations/aws/macros/ecr/private_repositories_have_tag_immutability_configured.sql index 4d46c0879..b0882b0be 100644 --- a/transformations/aws/macros/ecr/private_repositories_have_tag_immutability_configured.sql +++ b/transformations/aws/macros/ecr/private_repositories_have_tag_immutability_configured.sql @@ -1,4 +1,25 @@ {% macro private_repositories_have_tag_immutability_configured(framework, check_id) %} + {{ return(adapter.dispatch('private_repositories_have_tag_immutability_configured')(framework, check_id)) }} +{% endmacro %} + +{% macro default__private_repositories_have_tag_immutability_configured(framework, check_id) %}{% endmacro %} + +{% macro postgres__private_repositories_have_tag_immutability_configured(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'ECR private repositories should have tag immutability configured' as title, + account_id, + arn as resource_id, + CASE + WHEN image_tag_mutability <> 'IMMUTABLE' THEN 'fail' + ELSE 'pass' + END as status + FROM + aws_ecr_repositories +{% endmacro %} + +{% macro snowflake__private_repositories_have_tag_immutability_configured(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/ecr/repositories_have_at_least_one_lifecycle_policy.sql b/transformations/aws/macros/ecr/repositories_have_at_least_one_lifecycle_policy.sql index 8d5248cf1..3e2d25df9 100644 --- a/transformations/aws/macros/ecr/repositories_have_at_least_one_lifecycle_policy.sql +++ b/transformations/aws/macros/ecr/repositories_have_at_least_one_lifecycle_policy.sql @@ -1,4 +1,27 @@ {% macro repositories_have_at_least_one_lifecycle_policy(framework, check_id) %} + {{ return(adapter.dispatch('repositories_have_at_least_one_lifecycle_policy')(framework, check_id)) }} +{% endmacro %} + +{% macro default__repositories_have_at_least_one_lifecycle_policy(framework, check_id) %}{% endmacro %} + +{% macro postgres__repositories_have_at_least_one_lifecycle_policy(framework, check_id) %} +select DISTINCT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'ECR repositories should have at least one lifecycle policy configured' as title, + r.account_id, + r.arn as resource_id, + CASE + WHEN p.policy_json is null OR p.lifecycle_policy_text is null THEN 'fail' + ELSE 'pass' + END as status + FROM + aws_ecr_repositories r + LEFT JOIN aws_ecr_repository_lifecycle_policies p + ON r.repository_name = p.repository_name +{% endmacro %} + +{% macro snowflake__repositories_have_at_least_one_lifecycle_policy(framework, check_id) %} select DISTINCT '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/ecs/clusters_should_use_container_insights.sql b/transformations/aws/macros/ecs/clusters_should_use_container_insights.sql index 871b17c17..6f551df14 100644 --- a/transformations/aws/macros/ecs/clusters_should_use_container_insights.sql +++ b/transformations/aws/macros/ecs/clusters_should_use_container_insights.sql @@ -1,4 +1,38 @@ {% macro clusters_should_use_container_insights(framework, check_id) %} + {{ return(adapter.dispatch('clusters_should_use_container_insights')(framework, check_id)) }} +{% endmacro %} + +{% macro default__clusters_should_use_container_insights(framework, check_id) %}{% endmacro %} + +{% macro postgres__clusters_should_use_container_insights(framework, check_id) %} +with settings as ( +SELECT DISTINCT + arn +FROM + aws_ecs_clusters c, + JSONB_ARRAY_ELEMENTS(settings) as f +WHERE + f ->> 'Name' = 'containerInsights' + AND + f ->> 'Value' <> 'enabled' + ) +SELECT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'ECS clusters should use Container Insights' as title, + c.arn as resource_id, + c.account_id, + CASE + WHEN s.arn is not null THEN 'fail' + ELSE 'pass' + END as status +FROM + aws_ecs_clusters c +LEFT JOIN + settings s ON c.arn = s.arn +{% endmacro %} + +{% macro snowflake__clusters_should_use_container_insights(framework, check_id) %} with settings as ( SELECT DISTINCT arn diff --git a/transformations/aws/macros/ecs/containers_limited_read_only_root_filesystems.sql b/transformations/aws/macros/ecs/containers_limited_read_only_root_filesystems.sql index a1058f64a..7a8bf4ac0 100644 --- a/transformations/aws/macros/ecs/containers_limited_read_only_root_filesystems.sql +++ b/transformations/aws/macros/ecs/containers_limited_read_only_root_filesystems.sql @@ -1,4 +1,40 @@ {% macro containers_limited_read_only_root_filesystems(framework, check_id) %} + {{ return(adapter.dispatch('containers_limited_read_only_root_filesystems')(framework, check_id)) }} +{% endmacro %} + +{% macro default__containers_limited_read_only_root_filesystems(framework, check_id) %}{% endmacro %} + +{% macro postgres__containers_limited_read_only_root_filesystems(framework, check_id) %} +with flat_containers as ( + SELECT + arn, + account_id, + CASE + WHEN (container_definition ->> 'readonlyRootFilesystem')::BOOLEAN = FALSE + OR container_definition ->> 'readonlyRootFilesystem' IS NULL THEN 1 + ELSE 0 + END AS status + FROM + aws_ecs_task_definitions, + JSONB_ARRAY_ELEMENTS(container_definitions) as container_definition + WHERE + status = 'ACTIVE' + ) +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'ECS containers should be limited to read-only access to root filesystems' as title, + arn, + account_id, + CASE + WHEN max(status) OVER (PARTITION BY arn) = 1 THEN 'fail' + ELSE 'pass' + END as status +from + flat_containers +{% endmacro %} + +{% macro snowflake__containers_limited_read_only_root_filesystems(framework, check_id) %} with flat_containers as ( SELECT arn, diff --git a/transformations/aws/macros/ecs/containers_should_run_as_non_privileged.sql b/transformations/aws/macros/ecs/containers_should_run_as_non_privileged.sql index b9465444d..5e456559c 100644 --- a/transformations/aws/macros/ecs/containers_should_run_as_non_privileged.sql +++ b/transformations/aws/macros/ecs/containers_should_run_as_non_privileged.sql @@ -1,4 +1,40 @@ {% macro containers_should_run_as_non_privileged(framework, check_id) %} + {{ return(adapter.dispatch('containers_should_run_as_non_privileged')(framework, check_id)) }} +{% endmacro %} + +{% macro default__containers_should_run_as_non_privileged(framework, check_id) %}{% endmacro %} + +{% macro postgres__containers_should_run_as_non_privileged(framework, check_id) %} +with flat_containers as ( + SELECT + arn, + account_id, + CASE + WHEN (container_definition ->> 'Privileged')::BOOLEAN = TRUE THEN 1 + ELSE 0 + END AS status + FROM + aws_ecs_task_definitions, + JSONB_ARRAY_ELEMENTS(container_definitions) as container_definition + WHERE + status = 'ACTIVE' -- Only consider active task definitions + ) +select + DISTINCT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'ECS containers should run as non-privileged' as title, + arn as resource_id, + account_id, + CASE + WHEN max(status) OVER (PARTITION BY arn) = 1 THEN 'fail' + ELSE 'pass' + END as status +FROM + flat_containers +{% endmacro %} + +{% macro snowflake__containers_should_run_as_non_privileged(framework, check_id) %} with flat_containers as ( SELECT arn, diff --git a/transformations/aws/macros/ecs/fargate_should_run_on_latest_version.sql b/transformations/aws/macros/ecs/fargate_should_run_on_latest_version.sql index cae89c7c1..be868d568 100644 --- a/transformations/aws/macros/ecs/fargate_should_run_on_latest_version.sql +++ b/transformations/aws/macros/ecs/fargate_should_run_on_latest_version.sql @@ -1,4 +1,31 @@ {% macro fargate_should_run_on_latest_version(framework, check_id) %} + {{ return(adapter.dispatch('fargate_should_run_on_latest_version')(framework, check_id)) }} +{% endmacro %} + +{% macro default__fargate_should_run_on_latest_version(framework, check_id) %}{% endmacro %} + +{% macro postgres__fargate_should_run_on_latest_version(framework, check_id) %} +SELECT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'ECS Fargate services should run on the latest Fargate platform version' as title, + arn as resource_id, + account_id, + CASE + WHEN platform_version is null OR platform_version = 'LATEST' THEN 'pass' + WHEN (platform_family = 'LINUX' AND platform_version <> '1.4.0') + OR + (platform_family = 'WINDOWS' AND platform_version <> '1.0.0') + THEN 'fail' + ELSE 'pass' + END as status +FROM + aws_ecs_cluster_services +WHERE + launch_type = 'FARGATE' +{% endmacro %} + +{% macro snowflake__fargate_should_run_on_latest_version(framework, check_id) %} SELECT '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/ecs/secrets_should_not_be_in_environment_variables.sql b/transformations/aws/macros/ecs/secrets_should_not_be_in_environment_variables.sql index c8b37b415..4ddb0ea70 100644 --- a/transformations/aws/macros/ecs/secrets_should_not_be_in_environment_variables.sql +++ b/transformations/aws/macros/ecs/secrets_should_not_be_in_environment_variables.sql @@ -1,4 +1,45 @@ {% macro secrets_should_not_be_in_environment_variables(framework, check_id) %} + {{ return(adapter.dispatch('secrets_should_not_be_in_environment_variables')(framework, check_id)) }} +{% endmacro %} + +{% macro default__secrets_should_not_be_in_environment_variables(framework, check_id) %}{% endmacro %} + +{% macro postgres__secrets_should_not_be_in_environment_variables(framework, check_id) %} +with flat_containers AS ( +SELECT + t.arn, + t.account_id, + CASE + WHEN + f ->> 'environment' LIKE '%AWS_ACCESS_KEY_ID%' + OR + f ->> 'environment' LIKE '%AWS_SECRET_ACCESS_KEY%' + OR + f ->> 'environment' LIKE '%ECS_ENGINE_AUTH_DATA%' + THEN '1' + ELSE 0 + END as status +FROM + aws_ecs_task_definitions t, + JSONB_ARRAY_ELEMENTS(container_definitions) as f +WHERE + t.status = 'ACTIVE') + +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Secrets should not be passed as container environment variables' as title, + arn as resource_id, + account_id, + CASE + WHEN max(status) OVER (PARTITION BY arn) = 1 THEN 'fail' + ELSE 'pass' + END as status +from + flat_containers +{% endmacro %} + +{% macro snowflake__secrets_should_not_be_in_environment_variables(framework, check_id) %} with flat_containers AS ( SELECT t.arn, diff --git a/transformations/aws/macros/ecs/task_definitions_should_not_share_host_namespace.sql b/transformations/aws/macros/ecs/task_definitions_should_not_share_host_namespace.sql index b0430c1e6..9c9b9ba87 100644 --- a/transformations/aws/macros/ecs/task_definitions_should_not_share_host_namespace.sql +++ b/transformations/aws/macros/ecs/task_definitions_should_not_share_host_namespace.sql @@ -1,4 +1,27 @@ {% macro task_definitions_should_not_share_host_namespace(framework, check_id) %} + {{ return(adapter.dispatch('task_definitions_should_not_share_host_namespace')(framework, check_id)) }} +{% endmacro %} + +{% macro default__task_definitions_should_not_share_host_namespace(framework, check_id) %}{% endmacro %} + +{% macro postgres__task_definitions_should_not_share_host_namespace(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'ECS task definitions should not share the hosts process namespace' as title, + account_id, + arn as resource_id, + CASE + WHEN pid_mode = 'host' THEN 'fail' + ELSE 'pass' + END AS status +FROM + aws_ecs_task_definitions +WHERE + status = 'ACTIVE' +{% endmacro %} + +{% macro snowflake__task_definitions_should_not_share_host_namespace(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/eks/cluster_endpoints_not_publicly_accessible.sql b/transformations/aws/macros/eks/cluster_endpoints_not_publicly_accessible.sql index 172cb4fb6..41b4328da 100644 --- a/transformations/aws/macros/eks/cluster_endpoints_not_publicly_accessible.sql +++ b/transformations/aws/macros/eks/cluster_endpoints_not_publicly_accessible.sql @@ -1,4 +1,24 @@ {% macro cluster_endpoints_not_publicly_accessible(framework, check_id) %} + {{ return(adapter.dispatch('cluster_endpoints_not_publicly_accessible')(framework, check_id)) }} +{% endmacro %} + +{% macro default__cluster_endpoints_not_publicly_accessible(framework, check_id) %}{% endmacro %} + +{% macro postgres__cluster_endpoints_not_publicly_accessible(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'EKS cluster endpoints should not be publicly accessible' as title, + account_id, + arn as resource_id, + CASE + WHEN resources_vpc_config ->> 'endpointPublicAccess' = 'true' THEN 'fail' + ELSE 'pass' + END as status +FROM aws_eks_clusters +{% endmacro %} + +{% macro snowflake__cluster_endpoints_not_publicly_accessible(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/eks/clusters_should_run_on_supported_kuberneters_version.sql b/transformations/aws/macros/eks/clusters_should_run_on_supported_kuberneters_version.sql index 7626894c5..3b5718521 100644 --- a/transformations/aws/macros/eks/clusters_should_run_on_supported_kuberneters_version.sql +++ b/transformations/aws/macros/eks/clusters_should_run_on_supported_kuberneters_version.sql @@ -1,4 +1,24 @@ {% macro clusters_should_run_on_supported_kuberneters_version(framework, check_id) %} + {{ return(adapter.dispatch('clusters_should_run_on_supported_kuberneters_version')(framework, check_id)) }} +{% endmacro %} + +{% macro default__clusters_should_run_on_supported_kuberneters_version(framework, check_id) %}{% endmacro %} + +{% macro postgres__clusters_should_run_on_supported_kuberneters_version(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'EKS clusters should run on a supported Kubernetes version' as title, + account_id, + arn as resource_id, + CASE + WHEN version::float < 1.23 THEN 'fail' + ELSE 'pass' + END as status +FROM aws_eks_clusters +{% endmacro %} + +{% macro snowflake__clusters_should_run_on_supported_kuberneters_version(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/elasticache/clusters_should_not_use_default_subnet_group.sql b/transformations/aws/macros/elasticache/clusters_should_not_use_default_subnet_group.sql index e229da732..6346f9ce0 100644 --- a/transformations/aws/macros/elasticache/clusters_should_not_use_default_subnet_group.sql +++ b/transformations/aws/macros/elasticache/clusters_should_not_use_default_subnet_group.sql @@ -1,4 +1,25 @@ {% macro clusters_should_not_use_default_subnet_group(framework, check_id) %} + {{ return(adapter.dispatch('clusters_should_not_use_default_subnet_group')(framework, check_id)) }} +{% endmacro %} + +{% macro default__clusters_should_not_use_default_subnet_group(framework, check_id) %}{% endmacro %} + +{% macro postgres__clusters_should_not_use_default_subnet_group(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'ElastiCache clusters should not use the default subnet group' as title, + account_id, + arn as resource_id, + CASE + WHEN cache_subnet_group_name = 'default' THEN 'fail' + ELSE 'pass' + END as status +FROM + aws_elasticache_clusters +{% endmacro %} + +{% macro snowflake__clusters_should_not_use_default_subnet_group(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/elasticache/redis_clusters_have_autominorversionupgrade.sql b/transformations/aws/macros/elasticache/redis_clusters_have_autominorversionupgrade.sql index 0638a6870..cdee8fda2 100644 --- a/transformations/aws/macros/elasticache/redis_clusters_have_autominorversionupgrade.sql +++ b/transformations/aws/macros/elasticache/redis_clusters_have_autominorversionupgrade.sql @@ -1,4 +1,27 @@ {% macro redis_clusters_have_autominorversionupgrade(framework, check_id) %} + {{ return(adapter.dispatch('redis_clusters_have_autominorversionupgrade')(framework, check_id)) }} +{% endmacro %} + +{% macro default__redis_clusters_have_autominorversionupgrade(framework, check_id) %}{% endmacro %} + +{% macro postgres__redis_clusters_have_autominorversionupgrade(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Minor version upgrades should be automatically applied to ElastiCache for Redis cache clusters' as title, + account_id, + arn as resource_id, + CASE + WHEN auto_minor_version_upgrade = 'false' THEN 'fail' + ELSE 'pass' + END as status +FROM + aws_elasticache_clusters +WHERE + engine = 'redis' +{% endmacro %} + +{% macro snowflake__redis_clusters_have_autominorversionupgrade(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/elasticache/redis_clusters_should_have_automatic_backups.sql b/transformations/aws/macros/elasticache/redis_clusters_should_have_automatic_backups.sql index 9a9e41c56..543e3f180 100644 --- a/transformations/aws/macros/elasticache/redis_clusters_should_have_automatic_backups.sql +++ b/transformations/aws/macros/elasticache/redis_clusters_should_have_automatic_backups.sql @@ -1,4 +1,27 @@ {% macro redis_clusters_should_have_automatic_backups(framework, check_id) %} + {{ return(adapter.dispatch('redis_clusters_should_have_automatic_backups')(framework, check_id)) }} +{% endmacro %} + +{% macro default__redis_clusters_should_have_automatic_backups(framework, check_id) %}{% endmacro %} + +{% macro postgres__redis_clusters_should_have_automatic_backups(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'ElastiCache for Redis clusters should have automatic backups scheduled' as title, + account_id, + arn as resource_id, + CASE + WHEN (snapshot_retention_limit IS NULL OR snapshot_retention_limit < 1) THEN 'fail' + ELSE 'pass' + END as status +FROM + aws_elasticache_clusters +WHERE + engine = 'redis' +{% endmacro %} + +{% macro snowflake__redis_clusters_should_have_automatic_backups(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/elasticache/redis_replication_groups_automatic_failover_enabled.sql b/transformations/aws/macros/elasticache/redis_replication_groups_automatic_failover_enabled.sql index a8997fa1d..c90b51336 100644 --- a/transformations/aws/macros/elasticache/redis_replication_groups_automatic_failover_enabled.sql +++ b/transformations/aws/macros/elasticache/redis_replication_groups_automatic_failover_enabled.sql @@ -1,4 +1,25 @@ {% macro redis_replication_groups_automatic_failover_enabled(framework, check_id) %} + {{ return(adapter.dispatch('redis_replication_groups_automatic_failover_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__redis_replication_groups_automatic_failover_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__redis_replication_groups_automatic_failover_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'ElastiCache for Redis replication groups should have automatic failover enabled' as title, + account_id, + arn as resource_id, + CASE + WHEN automatic_failover <> 'enabled' THEN 'fail' + ELSE 'pass' + END as status +FROM + aws_elasticache_replication_groups +{% endmacro %} + +{% macro snowflake__redis_replication_groups_automatic_failover_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/elasticache/redis_replication_groups_encrypted_at_rest.sql b/transformations/aws/macros/elasticache/redis_replication_groups_encrypted_at_rest.sql index 8bcb6f4dc..ba0f5d557 100644 --- a/transformations/aws/macros/elasticache/redis_replication_groups_encrypted_at_rest.sql +++ b/transformations/aws/macros/elasticache/redis_replication_groups_encrypted_at_rest.sql @@ -1,4 +1,25 @@ {% macro redis_replication_groups_encrypted_at_rest(framework, check_id) %} + {{ return(adapter.dispatch('redis_replication_groups_encrypted_at_rest')(framework, check_id)) }} +{% endmacro %} + +{% macro default__redis_replication_groups_encrypted_at_rest(framework, check_id) %}{% endmacro %} + +{% macro postgres__redis_replication_groups_encrypted_at_rest(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'ElastiCache for Redis replication groups should be encrypted at rest' as title, + account_id, + arn as resource_id, + CASE + WHEN at_rest_encryption_enabled = 'true' THEN 'pass' + ELSE 'fail' + END as status +FROM + aws_elasticache_replication_groups +{% endmacro %} + +{% macro snowflake__redis_replication_groups_encrypted_at_rest(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/elasticache/redis_replication_groups_encrypted_in_transit.sql b/transformations/aws/macros/elasticache/redis_replication_groups_encrypted_in_transit.sql index d3df1df59..59cdf289d 100644 --- a/transformations/aws/macros/elasticache/redis_replication_groups_encrypted_in_transit.sql +++ b/transformations/aws/macros/elasticache/redis_replication_groups_encrypted_in_transit.sql @@ -1,4 +1,25 @@ {% macro redis_replication_groups_encrypted_in_transit(framework, check_id) %} + {{ return(adapter.dispatch('redis_replication_groups_encrypted_in_transit')(framework, check_id)) }} +{% endmacro %} + +{% macro default__redis_replication_groups_encrypted_in_transit(framework, check_id) %}{% endmacro %} + +{% macro postgres__redis_replication_groups_encrypted_in_transit(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'ElastiCache for Redis replication groups should be encrypted in transit' as title, + account_id, + arn as resource_id, + CASE + WHEN transit_encryption_enabled = 'false' OR transit_encryption_enabled IS NULL THEN 'fail' + ELSE 'pass' + END as status +FROM + aws_elasticache_replication_groups +{% endmacro %} + +{% macro snowflake__redis_replication_groups_encrypted_in_transit(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/elasticache/redis_replication_groups_under_version_6_use_auth.sql b/transformations/aws/macros/elasticache/redis_replication_groups_under_version_6_use_auth.sql index 2cfcb1497..d1030a71b 100644 --- a/transformations/aws/macros/elasticache/redis_replication_groups_under_version_6_use_auth.sql +++ b/transformations/aws/macros/elasticache/redis_replication_groups_under_version_6_use_auth.sql @@ -1,4 +1,27 @@ {% macro redis_replication_groups_under_version_6_use_auth(framework, check_id) %} + {{ return(adapter.dispatch('redis_replication_groups_under_version_6_use_auth')(framework, check_id)) }} +{% endmacro %} + +{% macro default__redis_replication_groups_under_version_6_use_auth(framework, check_id) %}{% endmacro %} + +{% macro postgres__redis_replication_groups_under_version_6_use_auth(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'ElastiCache for Redis replication groups before version 6.0 should use Redis AUTH' as title, + r.account_id, + r.arn as resource_id, + CASE + WHEN c.engine_version < '6.0' AND r.auth_token_enabled = 'false'THEN 'fail' + ELSE 'pass' + END as status +FROM + aws_elasticache_replication_groups r +JOIN + aws_elasticache_clusters c ON r.replication_group_id = c.replication_group_id +{% endmacro %} + +{% macro snowflake__redis_replication_groups_under_version_6_use_auth(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/elasticbeanstalk/elastic_beanstalk_stream_logs_to_cloudwatch.sql b/transformations/aws/macros/elasticbeanstalk/elastic_beanstalk_stream_logs_to_cloudwatch.sql index 1ab8c8e40..14ecf9e5f 100644 --- a/transformations/aws/macros/elasticbeanstalk/elastic_beanstalk_stream_logs_to_cloudwatch.sql +++ b/transformations/aws/macros/elasticbeanstalk/elastic_beanstalk_stream_logs_to_cloudwatch.sql @@ -1,4 +1,41 @@ {% macro elastic_beanstalk_stream_logs_to_cloudwatch(framework, check_id) %} + {{ return(adapter.dispatch('elastic_beanstalk_stream_logs_to_cloudwatch')(framework, check_id)) }} +{% endmacro %} + +{% macro default__elastic_beanstalk_stream_logs_to_cloudwatch(framework, check_id) %}{% endmacro %} + +{% macro postgres__elastic_beanstalk_stream_logs_to_cloudwatch(framework, check_id) %} +with flat_configs as ( + select + c.environment_arn, + f -> 'Namespace' ->> 'Value' as is_log_streaming + + from + aws_elasticbeanstalk_configuration_settings c, + JSONB_ARRAY_ELEMENTS(c.option_settings) AS f + + WHERE + f ->> 'Namespace' = 'aws:elasticbeanstalk:cloudwatch:logs' + and + f ->> 'OptionName' = 'StreamLogs' +) + +SELECT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Elastic Beanstalk should stream logs to CloudWatch' as title, + e.account_id, + e.arn as resource_id, + CASE + WHEN is_log_streaming = 'true' THEN 'pass' + ELSE 'fail' + END as status +FROM aws_elasticbeanstalk_environments e +JOIN flat_configs as fc + ON e.arn = fc.environment_arn +{% endmacro %} + +{% macro snowflake__elastic_beanstalk_stream_logs_to_cloudwatch(framework, check_id) %} with flat_configs as ( select c.environment_arn, diff --git a/transformations/aws/macros/elb/elbv1_desync_migration_mode_defensive_or_strictest.sql b/transformations/aws/macros/elb/elbv1_desync_migration_mode_defensive_or_strictest.sql index 7cc719404..f2987af09 100644 --- a/transformations/aws/macros/elb/elbv1_desync_migration_mode_defensive_or_strictest.sql +++ b/transformations/aws/macros/elb/elbv1_desync_migration_mode_defensive_or_strictest.sql @@ -1,4 +1,28 @@ {% macro elbv1_desync_migration_mode_defensive_or_strictest(framework, check_id) %} + {{ return(adapter.dispatch('elbv1_desync_migration_mode_defensive_or_strictest')(framework, check_id)) }} +{% endmacro %} + +{% macro default__elbv1_desync_migration_mode_defensive_or_strictest(framework, check_id) %}{% endmacro %} + +{% macro postgres__elbv1_desync_migration_mode_defensive_or_strictest(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Classic Load Balancer should be configured with defensive or strictest desync mitigation mode' as title, + account_id, + arn as resource_id, + case + WHEN aa ->> 'Value' in ('defensive', 'strictest') THEN 'pass' + ELSE 'fail' + END as status +FROM + aws_elbv1_load_balancers as lb, + JSONB_ARRAY_ELEMENTS(attributes -> 'AdditionalAttributes') AS aa +WHERE + aa ->> 'Key' = 'elb.http.desyncmitigationmode' +{% endmacro %} + +{% macro snowflake__elbv1_desync_migration_mode_defensive_or_strictest(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, @@ -13,5 +37,5 @@ FROM aws_elbv1_load_balancers as lb, LATERAL FLATTEN(input => attributes:AdditionalAttributes) aa WHERE - aa.value:Key = 'elb.http.desyncmitigationmode' + aa.value:Key = 'elb.http.desyncmitigationmode' {% endmacro %} \ No newline at end of file diff --git a/transformations/aws/macros/elb/elbv1_have_cross_zone_load_balancing.sql b/transformations/aws/macros/elb/elbv1_have_cross_zone_load_balancing.sql index f5085ebf6..278118d87 100644 --- a/transformations/aws/macros/elb/elbv1_have_cross_zone_load_balancing.sql +++ b/transformations/aws/macros/elb/elbv1_have_cross_zone_load_balancing.sql @@ -1,4 +1,25 @@ {% macro elbv1_have_cross_zone_load_balancing(framework, check_id) %} + {{ return(adapter.dispatch('elbv1_have_cross_zone_load_balancing')(framework, check_id)) }} +{% endmacro %} + +{% macro default__elbv1_have_cross_zone_load_balancing(framework, check_id) %}{% endmacro %} + +{% macro postgres__elbv1_have_cross_zone_load_balancing(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Classic Load Balancers should have cross-zone load balancing enabled' as title, + account_id, + arn as resource_id, + case + WHEN attributes -> 'CrossZoneLoadBalancing' ->> 'Enabled' = 'true' THEN 'pass' + ELSE 'fail' + END as status +FROM + aws_elbv1_load_balancers +{% endmacro %} + +{% macro snowflake__elbv1_have_cross_zone_load_balancing(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, @@ -10,5 +31,5 @@ select ELSE 'fail' END as status FROM - aws_elbv1_load_balancers + aws_elbv1_load_balancers {% endmacro %} \ No newline at end of file diff --git a/transformations/aws/macros/elb/elbv1_have_multiple_availability_zones.sql b/transformations/aws/macros/elb/elbv1_have_multiple_availability_zones.sql index 76e46f904..ce1504829 100644 --- a/transformations/aws/macros/elb/elbv1_have_multiple_availability_zones.sql +++ b/transformations/aws/macros/elb/elbv1_have_multiple_availability_zones.sql @@ -1,4 +1,25 @@ {% macro elbv1_have_multiple_availability_zones(framework, check_id) %} + {{ return(adapter.dispatch('elbv1_have_multiple_availability_zones')(framework, check_id)) }} +{% endmacro %} + +{% macro default__elbv1_have_multiple_availability_zones(framework, check_id) %}{% endmacro %} + +{% macro postgres__elbv1_have_multiple_availability_zones(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Classic Load Balancer should span multiple Availability Zones' as title, + account_id, + arn as resource_id, + case + WHEN array_length(availability_zones, 1) > 1 THEN 'pass' + ELSE 'fail' + END as status +FROM + aws_elbv1_load_balancers +{% endmacro %} + +{% macro snowflake__elbv1_have_multiple_availability_zones(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, @@ -10,5 +31,5 @@ select ELSE 'fail' END as status FROM - aws_elbv1_load_balancers + aws_elbv1_load_balancers {% endmacro %} \ No newline at end of file diff --git a/transformations/aws/macros/elb/elbv1_https_predefined_policy.sql b/transformations/aws/macros/elb/elbv1_https_predefined_policy.sql index 3e35ce210..962471bac 100644 --- a/transformations/aws/macros/elb/elbv1_https_predefined_policy.sql +++ b/transformations/aws/macros/elb/elbv1_https_predefined_policy.sql @@ -19,7 +19,6 @@ from aws_elbv1_load_balancers lb, lateral flatten(input => parse_json(lb.listene {% endmacro %} {% macro postgres__elbv1_https_predefined_policy(framework, check_id) %} -INSERT INTO aws_policy_results WITH flat_listeners AS ( SELECT arn, diff --git a/transformations/aws/macros/elbv2/elbv2_desync_migration_mode_defensive_or_strictest.sql b/transformations/aws/macros/elbv2/elbv2_desync_migration_mode_defensive_or_strictest.sql index 008190ea4..ad410f8a5 100644 --- a/transformations/aws/macros/elbv2/elbv2_desync_migration_mode_defensive_or_strictest.sql +++ b/transformations/aws/macros/elbv2/elbv2_desync_migration_mode_defensive_or_strictest.sql @@ -1,4 +1,25 @@ {% macro elbv2_desync_migration_mode_defensive_or_strictest(framework, check_id) %} + {{ return(adapter.dispatch('elbv2_desync_migration_mode_defensive_or_strictest')(framework, check_id)) }} +{% endmacro %} + +{% macro default__elbv2_desync_migration_mode_defensive_or_strictest(framework, check_id) %}{% endmacro %} + +{% macro postgres__elbv2_desync_migration_mode_defensive_or_strictest(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, +'Application Load Balancer should be configured with defensive or strictest desync mitigation mode' as title, + account_id, + load_balancer_arn as resource_id, + case + WHEN value in ('defensive', 'strictest') THEN 'pass' + ELSE 'fail' + END as status +from aws_elbv2_load_balancer_attributes +where key = 'routing.http.desync_mitigation_mode' +{% endmacro %} + +{% macro snowflake__elbv2_desync_migration_mode_defensive_or_strictest(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/elbv2/elbv2_have_multiple_availability_zones.sql b/transformations/aws/macros/elbv2/elbv2_have_multiple_availability_zones.sql index f31def8ff..779822da2 100644 --- a/transformations/aws/macros/elbv2/elbv2_have_multiple_availability_zones.sql +++ b/transformations/aws/macros/elbv2/elbv2_have_multiple_availability_zones.sql @@ -1,4 +1,25 @@ {% macro elbv2_have_multiple_availability_zones(framework, check_id) %} + {{ return(adapter.dispatch('elbv2_have_multiple_availability_zones')(framework, check_id)) }} +{% endmacro %} + +{% macro default__elbv2_have_multiple_availability_zones(framework, check_id) %}{% endmacro %} + +{% macro postgres__elbv2_have_multiple_availability_zones(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Application, Network and Gateway Load Balancers should span multiple Availability Zones' as title, + account_id, + arn as resource_id, + case + WHEN jsonb_array_length(availability_zones) > 1 THEN 'pass' + ELSE 'fail' + END as status +FROM + aws_elbv2_load_balancers +{% endmacro %} + +{% macro snowflake__elbv2_have_multiple_availability_zones(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, @@ -10,5 +31,5 @@ select ELSE 'fail' END as status FROM - aws_elbv2_load_balancers + aws_elbv2_load_balancers {% endmacro %} \ No newline at end of file diff --git a/transformations/aws/macros/kinesis/kinesis_stream_encrypted.sql b/transformations/aws/macros/kinesis/kinesis_stream_encrypted.sql index 267c6ffae..0e6eff60f 100644 --- a/transformations/aws/macros/kinesis/kinesis_stream_encrypted.sql +++ b/transformations/aws/macros/kinesis/kinesis_stream_encrypted.sql @@ -1,4 +1,23 @@ {% macro kinesis_stream_encrypted(framework, check_id) %} + {{ return(adapter.dispatch('kinesis_stream_encrypted')(framework, check_id)) }} +{% endmacro %} + +{% macro default__kinesis_stream_encrypted(framework, check_id) %}{% endmacro %} + +{% macro postgres__kinesis_stream_encrypted(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Kinesis streams should be encrypted at rest' as title, + account_id, + arn as resource_id, + case + WHEN ENCRYPTION_TYPE = 'KMS' THEN 'pass' + else 'fail' end as status +from aws_kinesis_streams +{% endmacro %} + +{% macro snowflake__kinesis_stream_encrypted(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/kms/iam_customer_policy_no_kms_decrypt.sql b/transformations/aws/macros/kms/iam_customer_policy_no_kms_decrypt.sql index f4ec0c67a..859dd1f8a 100644 --- a/transformations/aws/macros/kms/iam_customer_policy_no_kms_decrypt.sql +++ b/transformations/aws/macros/kms/iam_customer_policy_no_kms_decrypt.sql @@ -1,5 +1,4 @@ {% macro iam_customer_policy_no_kms_decrypt(framework, check_id) %} -wITH policy_with_decrypt AS ( {{ return(adapter.dispatch('iam_customer_policy_no_kms_decrypt')(framework, check_id)) }} {% endmacro %} diff --git a/transformations/aws/macros/kms/iam_inline_policy_no_kms_decrypt.sql b/transformations/aws/macros/kms/iam_inline_policy_no_kms_decrypt.sql index a145aa8d7..431b0a571 100644 --- a/transformations/aws/macros/kms/iam_inline_policy_no_kms_decrypt.sql +++ b/transformations/aws/macros/kms/iam_inline_policy_no_kms_decrypt.sql @@ -1,5 +1,120 @@ {% macro iam_inline_policy_no_kms_decrypt(framework, check_id) %} -wITH decrypt_users as ( + {{ return(adapter.dispatch('iam_inline_policy_no_kms_decrypt')(framework, check_id)) }} +{% endmacro %} + +{% macro default__iam_inline_policy_no_kms_decrypt(framework, check_id) %}{% endmacro %} + +{% macro postgres__iam_inline_policy_no_kms_decrypt(framework, check_id) %} +WITH decrypt_users as ( + SELECT DISTINCT + u.user_arn as arn + FROM + aws_iam_user_policies u, + JSONB_ARRAY_ELEMENTS(u.policy_document) AS inline_policy, + JSONB_ARRAY_ELEMENTS(inline_policy -> 'PolicyDocument' -> 'Statement') AS s + WHERE + s ->> 'Effect' = 'Allow' + AND + (s ->> 'Resource' = '*' OR + s ->> 'Resource' LIKE '%kms%') + AND + (s ->> 'Action' = '*' + OR s ->> 'Action' ILIKE '%kms:*%' + OR s ->> 'Action' ILIKE '%kms:decrypt%' + OR s ->> 'Action' ILIKE '%kms:reencryptfrom%' + OR s ->> 'Action' ILIKE '%kms:reencrypt*%') + +), +decrypt_roles as ( + SELECT DISTINCT + r.role_arn as arn + FROM + aws_iam_role_policies r, + JSONB_ARRAY_ELEMENTS(r.policy_document) AS inline_policy, + JSONB_ARRAY_ELEMENTS(inline_policy -> 'PolicyDocument' -> 'Statement') AS s + WHERE + s ->> 'Effect' = 'Allow' + AND + (s ->> 'Resource' = '*' OR + s ->> 'Resource' LIKE '%kms%') + AND + (s ->> 'Action' = '*' + OR s ->> 'Action' ILIKE '%kms:*%' + OR s ->> 'Action' ILIKE '%kms:decrypt%' + OR s ->> 'Action' ILIKE '%kms:reencryptfrom%' + OR s ->> 'Action' ILIKE '%kms:reencrypt*%') + AND r.role_arn NOT LIKE '%service-role/%' + +), +decrypt_groups as ( + SELECT DISTINCT + g.group_arn as arn + FROM + aws_iam_group_policies g, + JSONB_ARRAY_ELEMENTS(g.policy_document) AS inline_policy, + JSONB_ARRAY_ELEMENTS(inline_policy -> 'PolicyDocument' -> 'Statement') AS s + WHERE + s ->> 'Effect' = 'Allow' + AND + (s ->> 'Resource' = '*' OR + s ->> 'Resource' LIKE '%kms%') + AND + (s ->> 'Action' = '*' + OR s ->> 'Action' ILIKE '%kms:*%' + OR s ->> 'Action' ILIKE '%kms:decrypt%' + OR s ->> 'Action' ILIKE '%kms:reencryptfrom%' + OR s ->> 'Action' ILIKE '%kms:reencrypt*%') +) + +SELECT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'IAM principals should not have IAM inline policies that allow decryption actions on all KMS keys' AS title, + u.account_id, + u.arn as resource_id, + CASE + WHEN du.arn is not null THEN 'fail' + ELSE 'pass' + END as status +FROM aws_iam_users u +LEFT JOIN decrypt_users du + ON u.arn = du.arn + +UNION + +SELECT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'IAM principals should not have IAM inline policies that allow decryption actions on all KMS keys' AS title, + r.account_id, + r.arn as resource_id, + CASE + WHEN dr.arn is not null THEN 'fail' + ELSE 'pass' + END as status +FROM aws_iam_roles r +LEFT JOIN decrypt_roles dr + ON r.arn = dr.arn + +UNION + +SELECT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'IAM principals should not have IAM inline policies that allow decryption actions on all KMS keys' AS title, + g.account_id, + g.arn as resource_id, + CASE + WHEN dg.arn is not null THEN 'fail' + ELSE 'pass' + END as status +FROM aws_iam_groups g +LEFT JOIN decrypt_groups dg + ON g.arn = dg.arn +{% endmacro %} + +{% macro snowflake__iam_inline_policy_no_kms_decrypt(framework, check_id) %} +WITH decrypt_users as ( SELECT DISTINCT u.user_arn as arn FROM diff --git a/transformations/aws/macros/kms/key_rotation_enabled.sql b/transformations/aws/macros/kms/key_rotation_enabled.sql index a2755e686..129af7e6c 100644 --- a/transformations/aws/macros/kms/key_rotation_enabled.sql +++ b/transformations/aws/macros/kms/key_rotation_enabled.sql @@ -1,4 +1,25 @@ {% macro key_rotation_enabled(framework, check_id) %} + {{ return(adapter.dispatch('key_rotation_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__key_rotation_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__key_rotation_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'AWS KMS key rotation should be enabled' AS title, + account_id, + arn AS resource_id, + CASE + WHEN (rotation_enabled = false or rotation_enabled is null) AND key_manager = 'CUSTOMER' THEN 'fail' + ELSE 'pass' + END as status +FROM + aws_kms_keys +{% endmacro %} + +{% macro snowflake__key_rotation_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/kms/keys_not_unintentionally_deleted.sql b/transformations/aws/macros/kms/keys_not_unintentionally_deleted.sql index 45bfe9cb8..367596c92 100644 --- a/transformations/aws/macros/kms/keys_not_unintentionally_deleted.sql +++ b/transformations/aws/macros/kms/keys_not_unintentionally_deleted.sql @@ -1,4 +1,25 @@ {% macro keys_not_unintentionally_deleted(framework, check_id) %} + {{ return(adapter.dispatch('keys_not_unintentionally_deleted')(framework, check_id)) }} +{% endmacro %} + +{% macro default__keys_not_unintentionally_deleted(framework, check_id) %}{% endmacro %} + +{% macro postgres__keys_not_unintentionally_deleted(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'AWS KMS keys should not be deleted unintentionally' AS title, + account_id, + arn AS resource_id, + CASE + WHEN key_state IN ('PendingDeletion', 'PendingReplicaDeletion') AND key_manager = 'CUSTOMER' THEN 'fail' + ELSE 'pass' + END AS status +FROM + aws_kms_keys +{% endmacro %} + +{% macro snowflake__keys_not_unintentionally_deleted(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/lambda/lambda_function_public_access_prohibited.sql b/transformations/aws/macros/lambda/lambda_function_public_access_prohibited.sql index 97a0e244a..1a7f2b9e4 100644 --- a/transformations/aws/macros/lambda/lambda_function_public_access_prohibited.sql +++ b/transformations/aws/macros/lambda/lambda_function_public_access_prohibited.sql @@ -1,4 +1,34 @@ {% macro lambda_function_public_access_prohibited(framework, check_id) %} + {{ return(adapter.dispatch('lambda_function_public_access_prohibited')(framework, check_id)) }} +{% endmacro %} + +{% macro default__lambda_function_public_access_prohibited(framework, check_id) %}{% endmacro %} + +{% macro postgres__lambda_function_public_access_prohibited(framework, check_id) %} +select DISTINCT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Lambda function policies should prohibit public access' AS title, + account_id, + arn AS resource_id, + 'fail' AS status +FROM ( + SELECT + account_id, + arn + FROM + aws_lambda_functions, + JSONB_ARRAY_ELEMENTS(policy_document->'Statement') as statement +where + statement ->> 'Effect' = 'Allow' + and + statement ->> 'Principal' = '*' + or + statement -> 'Principal' ->> 'AWS' = '*' + ) as a +{% endmacro %} + +{% macro snowflake__lambda_function_public_access_prohibited(framework, check_id) %} select DISTINCT '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/lambda/lambda_inside_vpc.sql b/transformations/aws/macros/lambda/lambda_inside_vpc.sql index 32319a4d5..8dee09b12 100644 --- a/transformations/aws/macros/lambda/lambda_inside_vpc.sql +++ b/transformations/aws/macros/lambda/lambda_inside_vpc.sql @@ -1,4 +1,28 @@ {% macro lambda_inside_vpc(framework, check_id) %} + {{ return(adapter.dispatch('lambda_inside_vpc')(framework, check_id)) }} +{% endmacro %} + +{% macro default__lambda_inside_vpc(framework, check_id) %}{% endmacro %} + +{% macro postgres__lambda_inside_vpc(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Lambda functions should be in a VPC' AS title, + account_id, + arn AS resource_id, + CASE + WHEN (configuration -> 'VpcConfig' ->> 'VpcId') IS NULL + OR configuration -> 'VpcConfig' ->> 'VpcId' = '' + THEN 'fail' + ELSE 'pass' + END + AS status +FROM + aws_lambda_functions +{% endmacro %} + +{% macro snowflake__lambda_inside_vpc(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/lambda/lambda_vpc_multi_az_check.sql b/transformations/aws/macros/lambda/lambda_vpc_multi_az_check.sql index a7f183eb7..88a9c6983 100644 --- a/transformations/aws/macros/lambda/lambda_vpc_multi_az_check.sql +++ b/transformations/aws/macros/lambda/lambda_vpc_multi_az_check.sql @@ -1,4 +1,31 @@ {% macro lambda_vpc_multi_az_check(framework, check_id) %} + {{ return(adapter.dispatch('lambda_vpc_multi_az_check')(framework, check_id)) }} +{% endmacro %} + +{% macro default__lambda_vpc_multi_az_check(framework, check_id) %}{% endmacro %} + +{% macro postgres__lambda_vpc_multi_az_check(framework, check_id) %} +SELECT + '{{framework}}' AS framework, + '{{check_id}}' AS check_id, + 'VPC Lambda functions should operate in more than one Availability Zone' AS title, + account_id, + l.arn AS resource_id, + CASE + WHEN COUNT(DISTINCT s.availability_zone_id) > 1 THEN 'pass' + ELSE 'fail' + END AS status +FROM + aws_lambda_functions AS l +INNER JOIN + JSONB_ARRAY_ELEMENTS(l.configuration->'VpcConfig'->'SubnetIds') AS a ON TRUE +LEFT JOIN + aws_ec2_subnets AS s ON a.value::text = s.subnet_id +GROUP BY + l.arn, account_id +{% endmacro %} + +{% macro snowflake__lambda_vpc_multi_az_check(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/neptune/neptune_cluster_backup_retention_check.sql b/transformations/aws/macros/neptune/neptune_cluster_backup_retention_check.sql index aa80ac634..9db562fe5 100644 --- a/transformations/aws/macros/neptune/neptune_cluster_backup_retention_check.sql +++ b/transformations/aws/macros/neptune/neptune_cluster_backup_retention_check.sql @@ -1,4 +1,27 @@ {% macro neptune_cluster_backup_retention_check(framework, check_id) %} + {{ return(adapter.dispatch('neptune_cluster_backup_retention_check')(framework, check_id)) }} +{% endmacro %} + +{% macro default__neptune_cluster_backup_retention_check(framework, check_id) %}{% endmacro %} + +{% macro postgres__neptune_cluster_backup_retention_check(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Neptune DB clusters should have automated backups enabled' as title, + account_id, + arn as resource_id, + case when + backup_retention_period IS NULL + OR backup_retention_period < 7 + then 'fail' + else 'pass' + end as status +from + aws_neptune_clusters +{% endmacro %} + +{% macro snowflake__neptune_cluster_backup_retention_check(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/neptune/neptune_cluster_cloudwatch_log_export_enabled.sql b/transformations/aws/macros/neptune/neptune_cluster_cloudwatch_log_export_enabled.sql index 47765c868..e3e472a50 100644 --- a/transformations/aws/macros/neptune/neptune_cluster_cloudwatch_log_export_enabled.sql +++ b/transformations/aws/macros/neptune/neptune_cluster_cloudwatch_log_export_enabled.sql @@ -1,4 +1,25 @@ {% macro neptune_cluster_cloudwatch_log_export_enabled(framework, check_id) %} + {{ return(adapter.dispatch('neptune_cluster_cloudwatch_log_export_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__neptune_cluster_cloudwatch_log_export_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__neptune_cluster_cloudwatch_log_export_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Neptune DB clusters should publish audit logs to CloudWatch Logs' as title, + account_id, + arn as resource_id, + case when + ARRAY['audit'] <@ ENABLED_CLOUDWATCH_LOGS_EXPORTS then 'pass' + else 'fail' + end as status +from + aws_neptune_clusters +{% endmacro %} + +{% macro snowflake__neptune_cluster_cloudwatch_log_export_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/neptune/neptune_cluster_copy_tags_to_snapshot_enabled.sql b/transformations/aws/macros/neptune/neptune_cluster_copy_tags_to_snapshot_enabled.sql index 2bd6efae9..8f344ed9f 100644 --- a/transformations/aws/macros/neptune/neptune_cluster_copy_tags_to_snapshot_enabled.sql +++ b/transformations/aws/macros/neptune/neptune_cluster_copy_tags_to_snapshot_enabled.sql @@ -1,4 +1,25 @@ {% macro neptune_cluster_copy_tags_to_snapshot_enabled(framework, check_id) %} + {{ return(adapter.dispatch('neptune_cluster_copy_tags_to_snapshot_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__neptune_cluster_copy_tags_to_snapshot_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__neptune_cluster_copy_tags_to_snapshot_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Neptune DB clusters should be configured to copy tags to snapshots' as title, + account_id, + arn as resource_id, + case when + copy_tags_to_snapshot = true then 'pass' + else 'fail' + end as status +from + aws_neptune_clusters +{% endmacro %} + +{% macro snowflake__neptune_cluster_copy_tags_to_snapshot_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/neptune/neptune_cluster_deletion_protection_enabled.sql b/transformations/aws/macros/neptune/neptune_cluster_deletion_protection_enabled.sql index 348415063..0a1d2ec8f 100644 --- a/transformations/aws/macros/neptune/neptune_cluster_deletion_protection_enabled.sql +++ b/transformations/aws/macros/neptune/neptune_cluster_deletion_protection_enabled.sql @@ -1,4 +1,25 @@ {% macro neptune_cluster_deletion_protection_enabled(framework, check_id) %} + {{ return(adapter.dispatch('neptune_cluster_deletion_protection_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__neptune_cluster_deletion_protection_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__neptune_cluster_deletion_protection_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Neptune DB clusters should have deletion protection enabled' as title, + account_id, + arn as resource_id, + case when + deletion_protection = true then 'pass' + else 'fail' + end as status +from + aws_neptune_clusters +{% endmacro %} + +{% macro snowflake__neptune_cluster_deletion_protection_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/neptune/neptune_cluster_encrypted.sql b/transformations/aws/macros/neptune/neptune_cluster_encrypted.sql index e499650f4..c3d4fa724 100644 --- a/transformations/aws/macros/neptune/neptune_cluster_encrypted.sql +++ b/transformations/aws/macros/neptune/neptune_cluster_encrypted.sql @@ -1,4 +1,25 @@ {% macro neptune_cluster_encrypted(framework, check_id) %} + {{ return(adapter.dispatch('neptune_cluster_encrypted')(framework, check_id)) }} +{% endmacro %} + +{% macro default__neptune_cluster_encrypted(framework, check_id) %}{% endmacro %} + +{% macro postgres__neptune_cluster_encrypted(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Neptune DB clusters should be encrypted at rest' as title, + account_id, + arn as resource_id, + case when + storage_encrypted = true then 'pass' + else 'fail' + end as status +from + aws_neptune_clusters +{% endmacro %} + +{% macro snowflake__neptune_cluster_encrypted(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/neptune/neptune_cluster_iam_database_authentication.sql b/transformations/aws/macros/neptune/neptune_cluster_iam_database_authentication.sql index c2650252c..cfe7e4650 100644 --- a/transformations/aws/macros/neptune/neptune_cluster_iam_database_authentication.sql +++ b/transformations/aws/macros/neptune/neptune_cluster_iam_database_authentication.sql @@ -1,4 +1,25 @@ {% macro neptune_cluster_iam_database_authentication(framework, check_id) %} + {{ return(adapter.dispatch('neptune_cluster_iam_database_authentication')(framework, check_id)) }} +{% endmacro %} + +{% macro default__neptune_cluster_iam_database_authentication(framework, check_id) %}{% endmacro %} + +{% macro postgres__neptune_cluster_iam_database_authentication(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Neptune DB clusters should have IAM database authentication enabled' as title, + account_id, + arn as resource_id, + case when + iam_database_authentication_enabled = true then 'pass' + else 'fail' + end as status +from + aws_neptune_clusters +{% endmacro %} + +{% macro snowflake__neptune_cluster_iam_database_authentication(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/neptune/neptune_cluster_snapshot_encrypted.sql b/transformations/aws/macros/neptune/neptune_cluster_snapshot_encrypted.sql index ae25837c6..3b8679633 100644 --- a/transformations/aws/macros/neptune/neptune_cluster_snapshot_encrypted.sql +++ b/transformations/aws/macros/neptune/neptune_cluster_snapshot_encrypted.sql @@ -1,4 +1,25 @@ {% macro neptune_cluster_snapshot_encrypted(framework, check_id) %} + {{ return(adapter.dispatch('neptune_cluster_snapshot_encrypted')(framework, check_id)) }} +{% endmacro %} + +{% macro default__neptune_cluster_snapshot_encrypted(framework, check_id) %}{% endmacro %} + +{% macro postgres__neptune_cluster_snapshot_encrypted(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Neptune DB cluster snapshots should be encrypted at rest' as title, + account_id, + arn as resource_id, + case when + storage_encrypted = true then 'pass' + else 'fail' + end as status +from + aws_neptune_cluster_snapshots +{% endmacro %} + +{% macro snowflake__neptune_cluster_snapshot_encrypted(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/neptune/neptune_cluster_snapshot_public_prohibited.sql b/transformations/aws/macros/neptune/neptune_cluster_snapshot_public_prohibited.sql index f291d64f8..6f23d49ff 100644 --- a/transformations/aws/macros/neptune/neptune_cluster_snapshot_public_prohibited.sql +++ b/transformations/aws/macros/neptune/neptune_cluster_snapshot_public_prohibited.sql @@ -1,4 +1,27 @@ {% macro neptune_cluster_snapshot_public_prohibited(framework, check_id) %} + {{ return(adapter.dispatch('neptune_cluster_snapshot_public_prohibited')(framework, check_id)) }} +{% endmacro %} + +{% macro default__neptune_cluster_snapshot_public_prohibited(framework, check_id) %}{% endmacro %} + +{% macro postgres__neptune_cluster_snapshot_public_prohibited(framework, check_id) %} +SELECT + '{{framework}}' AS framework, + '{{check_id}}' AS check_id, + 'Neptune DB cluster snapshots should not be public' AS title, + account_id, + arn AS resource_id, + CASE + WHEN a ->> 'AttributeName' = 'restore' AND a -> 'AttributeValues' ? 'all' + THEN 'fail' + ELSE 'pass' + END AS status +FROM + aws_neptune_cluster_snapshots, + JSONB_ARRAY_ELEMENTS(attributes) AS a +{% endmacro %} + +{% macro snowflake__neptune_cluster_snapshot_public_prohibited(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/networkfirewall/netfw_policy_default_action_fragment_packets.sql b/transformations/aws/macros/networkfirewall/netfw_policy_default_action_fragment_packets.sql index fdeb12b23..40c7c5d93 100644 --- a/transformations/aws/macros/networkfirewall/netfw_policy_default_action_fragment_packets.sql +++ b/transformations/aws/macros/networkfirewall/netfw_policy_default_action_fragment_packets.sql @@ -1,4 +1,26 @@ {% macro netfw_policy_default_action_fragment_packets(framework, check_id) %} + {{ return(adapter.dispatch('netfw_policy_default_action_fragment_packets')(framework, check_id)) }} +{% endmacro %} + +{% macro default__netfw_policy_default_action_fragment_packets(framework, check_id) %}{% endmacro %} + +{% macro postgres__netfw_policy_default_action_fragment_packets(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'The default stateless action for Network Firewall policies should be drop or forward for fragmented packets' as title, + account_id, + arn as resource_id, + CASE + WHEN + stateless_fragment_default_actions[0] = 'aws:drop' or stateless_fragment_default_actions[0] = 'aws:forward_to_sfe' then 'pass' + else 'fail' + END AS status +FROM + aws_networkfirewall_firewall_policies +{% endmacro %} + +{% macro snowflake__netfw_policy_default_action_fragment_packets(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/networkfirewall/netfw_policy_default_action_full_packets.sql b/transformations/aws/macros/networkfirewall/netfw_policy_default_action_full_packets.sql index f17dcacac..de65693b6 100644 --- a/transformations/aws/macros/networkfirewall/netfw_policy_default_action_full_packets.sql +++ b/transformations/aws/macros/networkfirewall/netfw_policy_default_action_full_packets.sql @@ -1,4 +1,26 @@ {% macro netfw_policy_default_action_full_packets(framework, check_id) %} + {{ return(adapter.dispatch('netfw_policy_default_action_full_packets')(framework, check_id)) }} +{% endmacro %} + +{% macro default__netfw_policy_default_action_full_packets(framework, check_id) %}{% endmacro %} + +{% macro postgres__netfw_policy_default_action_full_packets(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'The default stateless action for Network Firewall policies should be drop or forward for full packets' as title, + account_id, + arn as resource_id, + CASE + WHEN + stateless_default_actions[0] = 'aws:drop' or stateless_default_actions[0] = 'aws:forward_to_sfe' then 'pass' + else 'fail' + END AS status +FROM + aws_networkfirewall_firewall_policies +{% endmacro %} + +{% macro snowflake__netfw_policy_default_action_full_packets(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/networkfirewall/netfw_policy_rule_group_associated.sql b/transformations/aws/macros/networkfirewall/netfw_policy_rule_group_associated.sql index 12be9e9d1..ffd278afd 100644 --- a/transformations/aws/macros/networkfirewall/netfw_policy_rule_group_associated.sql +++ b/transformations/aws/macros/networkfirewall/netfw_policy_rule_group_associated.sql @@ -1,4 +1,25 @@ {% macro netfw_policy_rule_group_associated(framework, check_id) %} + {{ return(adapter.dispatch('netfw_policy_rule_group_associated')(framework, check_id)) }} +{% endmacro %} + +{% macro default__netfw_policy_rule_group_associated(framework, check_id) %}{% endmacro %} + +{% macro postgres__netfw_policy_rule_group_associated(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Network Firewall policies should have at least one rule group associated' as title, + account_id, + arn as resource_id, + CASE + WHEN jsonb_array_length(stateful_rule_group_references) > 0 OR jsonb_array_length(stateless_rule_group_references) > 0 then 'pass' + else 'fail' + END AS status +FROM + aws_networkfirewall_firewall_policies +{% endmacro %} + +{% macro snowflake__netfw_policy_rule_group_associated(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/networkfirewall/netfw_stateless_rule_group_not_empty.sql b/transformations/aws/macros/networkfirewall/netfw_stateless_rule_group_not_empty.sql index 48138a2f5..f3b35a01c 100644 --- a/transformations/aws/macros/networkfirewall/netfw_stateless_rule_group_not_empty.sql +++ b/transformations/aws/macros/networkfirewall/netfw_stateless_rule_group_not_empty.sql @@ -1,4 +1,30 @@ {% macro netfw_stateless_rule_group_not_empty(framework, check_id) %} + {{ return(adapter.dispatch('netfw_stateless_rule_group_not_empty')(framework, check_id)) }} +{% endmacro %} + +{% macro default__netfw_stateless_rule_group_not_empty(framework, check_id) %}{% endmacro %} + +{% macro postgres__netfw_stateless_rule_group_not_empty(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Stateless Network Firewall rule group should not be empty' as title, + account_id, + arn as resource_id, + CASE + WHEN + RULES_SOURCE -> 'StatelessRulesAndCustomActions' ->> 'StatelessRules' is NULL and type = 'STATELESS' + then 'fail' + WHEN + jsonb_array_length(RULES_SOURCE -> 'StatelessRulesAndCustomActions' -> 'StatelessRules') = 0 and type = 'STATELESS' + then 'fail' + else 'pass' + END AS status +FROM + aws_networkfirewall_rule_groups +{% endmacro %} + +{% macro snowflake__netfw_stateless_rule_group_not_empty(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, @@ -15,5 +41,5 @@ select else 'pass' END AS status FROM - aws_networkfirewall_rule_groups + aws_networkfirewall_rule_groups {% endmacro %} \ No newline at end of file diff --git a/transformations/aws/macros/rds/cluster_snapshots_and_database_snapshots_should_be_encrypted_at_rest.sql b/transformations/aws/macros/rds/cluster_snapshots_and_database_snapshots_should_be_encrypted_at_rest.sql index 359dfe0ff..63c15612b 100644 --- a/transformations/aws/macros/rds/cluster_snapshots_and_database_snapshots_should_be_encrypted_at_rest.sql +++ b/transformations/aws/macros/rds/cluster_snapshots_and_database_snapshots_should_be_encrypted_at_rest.sql @@ -1,5 +1,34 @@ {% macro cluster_snapshots_and_database_snapshots_should_be_encrypted_at_rest(framework, check_id) %} + {{ return(adapter.dispatch('cluster_snapshots_and_database_snapshots_should_be_encrypted_at_rest')(framework, check_id)) }} +{% endmacro %} +{% macro default__cluster_snapshots_and_database_snapshots_should_be_encrypted_at_rest(framework, check_id) %}{% endmacro %} + +{% macro postgres__cluster_snapshots_and_database_snapshots_should_be_encrypted_at_rest(framework, check_id) %} +( +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS cluster snapshots and database snapshots should be encrypted at rest' as title, + account_id, + arn AS resource_id, + case when storage_encrypted != TRUE then 'fail' else 'pass' end as status +from aws_rds_cluster_snapshots +) +union +( + select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS cluster snapshots and database snapshots should be encrypted at rest' as title, + account_id, + arn AS resource_id, + case when encrypted != TRUE then 'fail' else 'pass' end as status + from aws_rds_db_snapshots +) +{% endmacro %} + +{% macro snowflake__cluster_snapshots_and_database_snapshots_should_be_encrypted_at_rest(framework, check_id) %} ( select '{{framework}}' As framework, diff --git a/transformations/aws/macros/rds/clusters_should_be_configured_for_multiple_availability_zones.sql b/transformations/aws/macros/rds/clusters_should_be_configured_for_multiple_availability_zones.sql index e7e15374c..39151e3a9 100644 --- a/transformations/aws/macros/rds/clusters_should_be_configured_for_multiple_availability_zones.sql +++ b/transformations/aws/macros/rds/clusters_should_be_configured_for_multiple_availability_zones.sql @@ -1,4 +1,21 @@ {% macro clusters_should_be_configured_for_multiple_availability_zones(framework, check_id) %} + {{ return(adapter.dispatch('clusters_should_be_configured_for_multiple_availability_zones')(framework, check_id)) }} +{% endmacro %} + +{% macro default__clusters_should_be_configured_for_multiple_availability_zones(framework, check_id) %}{% endmacro %} + +{% macro postgres__clusters_should_be_configured_for_multiple_availability_zones(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS DB clusters should be configured for multiple Availability Zones' as title, + account_id, + arn AS resource_id, + case when multi_az != TRUE then 'fail' else 'pass' end as status +from aws_rds_clusters +{% endmacro %} + +{% macro snowflake__clusters_should_be_configured_for_multiple_availability_zones(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/clusters_should_be_configured_to_copy_tags_to_snapshots.sql b/transformations/aws/macros/rds/clusters_should_be_configured_to_copy_tags_to_snapshots.sql index 13e76865f..947ab11a2 100644 --- a/transformations/aws/macros/rds/clusters_should_be_configured_to_copy_tags_to_snapshots.sql +++ b/transformations/aws/macros/rds/clusters_should_be_configured_to_copy_tags_to_snapshots.sql @@ -1,4 +1,21 @@ {% macro clusters_should_be_configured_to_copy_tags_to_snapshots(framework, check_id) %} + {{ return(adapter.dispatch('clusters_should_be_configured_to_copy_tags_to_snapshots')(framework, check_id)) }} +{% endmacro %} + +{% macro default__clusters_should_be_configured_to_copy_tags_to_snapshots(framework, check_id) %}{% endmacro %} + +{% macro postgres__clusters_should_be_configured_to_copy_tags_to_snapshots(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS DB clusters should be configured to copy tags to snapshots' as title, + account_id, + arn AS resource_id, + case when copy_tags_to_snapshot != TRUE then 'fail' else 'pass' end as status +from aws_rds_clusters +{% endmacro %} + +{% macro snowflake__clusters_should_be_configured_to_copy_tags_to_snapshots(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/clusters_should_have_deletion_protection_enabled.sql b/transformations/aws/macros/rds/clusters_should_have_deletion_protection_enabled.sql index e1834c947..635183b12 100644 --- a/transformations/aws/macros/rds/clusters_should_have_deletion_protection_enabled.sql +++ b/transformations/aws/macros/rds/clusters_should_have_deletion_protection_enabled.sql @@ -1,4 +1,21 @@ {% macro clusters_should_have_deletion_protection_enabled(framework, check_id) %} + {{ return(adapter.dispatch('clusters_should_have_deletion_protection_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__clusters_should_have_deletion_protection_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__clusters_should_have_deletion_protection_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS clusters should have deletion protection enabled' as title, + account_id, + arn AS resource_id, + case when deletion_protection != TRUE then 'fail' else 'pass' end as status +from aws_rds_clusters +{% endmacro %} + +{% macro snowflake__clusters_should_have_deletion_protection_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/databases_and_clusters_should_not_use_database_engine_default_port.sql b/transformations/aws/macros/rds/databases_and_clusters_should_not_use_database_engine_default_port.sql index b19318f02..2d621b027 100644 --- a/transformations/aws/macros/rds/databases_and_clusters_should_not_use_database_engine_default_port.sql +++ b/transformations/aws/macros/rds/databases_and_clusters_should_not_use_database_engine_default_port.sql @@ -1,5 +1,44 @@ {% macro databases_and_clusters_should_not_use_database_engine_default_port(framework, check_id) %} + {{ return(adapter.dispatch('databases_and_clusters_should_not_use_database_engine_default_port')(framework, check_id)) }} +{% endmacro %} +{% macro default__databases_and_clusters_should_not_use_database_engine_default_port(framework, check_id) %}{% endmacro %} + +{% macro postgres__databases_and_clusters_should_not_use_database_engine_default_port(framework, check_id) %} +( + SELECT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS databases and clusters should not use a database engine default port' AS title, + account_id, + arn AS resource_id, + CASE WHEN + (engine IN ('aurora', 'aurora-mysql', 'mysql') AND port = 3306) OR (engine LIKE '%postgres%' AND port = 5432) + THEN 'fail' ELSE 'pass' END AS status + FROM aws_rds_clusters +) +UNION ALL +( + SELECT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS databases and clusters should not use a database engine default port' AS title, + account_id, + arn AS resource_id, + CASE WHEN + ( + engine IN ('aurora', 'aurora-mysql', 'mariadb', 'mysql') + AND db_instance_port = 3306 + ) + OR (engine LIKE '%postgres%' AND db_instance_port = 5432) + OR (engine LIKE '%oracle%' AND db_instance_port = 1521) + OR (engine LIKE '%sqlserver%' AND db_instance_port = 1433) + THEN 'fail' ELSE 'pass' END AS status + FROM aws_rds_instances +) +{% endmacro %} + +{% macro snowflake__databases_and_clusters_should_not_use_database_engine_default_port(framework, check_id) %} ( SELECT '{{framework}}' As framework, diff --git a/transformations/aws/macros/rds/db_instance_backup_enabled.sql b/transformations/aws/macros/rds/db_instance_backup_enabled.sql index 96dca32ef..b24019a6c 100644 --- a/transformations/aws/macros/rds/db_instance_backup_enabled.sql +++ b/transformations/aws/macros/rds/db_instance_backup_enabled.sql @@ -1,4 +1,26 @@ {% macro db_instance_backup_enabled(framework, check_id) %} + {{ return(adapter.dispatch('db_instance_backup_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__db_instance_backup_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__db_instance_backup_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS instances should have automatic backups enabled' as title, + account_id, + arn AS resource_id, + CASE + WHEN backup_retention_period IS NULL + OR backup_retention_period < 7 THEN 'fail' + ELSE 'pass' + END AS status +FROM + aws_rds_instances +{% endmacro %} + +{% macro snowflake__db_instance_backup_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/enhanced_monitoring_should_be_configured_for_instances_and_clusters.sql b/transformations/aws/macros/rds/enhanced_monitoring_should_be_configured_for_instances_and_clusters.sql index 8e2eb51eb..92cd27311 100644 --- a/transformations/aws/macros/rds/enhanced_monitoring_should_be_configured_for_instances_and_clusters.sql +++ b/transformations/aws/macros/rds/enhanced_monitoring_should_be_configured_for_instances_and_clusters.sql @@ -1,4 +1,21 @@ {% macro enhanced_monitoring_should_be_configured_for_instances_and_clusters(framework, check_id) %} + {{ return(adapter.dispatch('enhanced_monitoring_should_be_configured_for_instances_and_clusters')(framework, check_id)) }} +{% endmacro %} + +{% macro default__enhanced_monitoring_should_be_configured_for_instances_and_clusters(framework, check_id) %}{% endmacro %} + +{% macro postgres__enhanced_monitoring_should_be_configured_for_instances_and_clusters(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Enhanced monitoring should be configured for RDS DB instances and clusters' as title, + account_id, + arn AS resource_id, + case when enhanced_monitoring_resource_arn is null then 'fail' else 'pass' end as status +from aws_rds_instances +{% endmacro %} + +{% macro snowflake__enhanced_monitoring_should_be_configured_for_instances_and_clusters(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/instances_should_be_configured_to_copy_tags_to_snapshots.sql b/transformations/aws/macros/rds/instances_should_be_configured_to_copy_tags_to_snapshots.sql index c647b88d1..97c6c5f34 100644 --- a/transformations/aws/macros/rds/instances_should_be_configured_to_copy_tags_to_snapshots.sql +++ b/transformations/aws/macros/rds/instances_should_be_configured_to_copy_tags_to_snapshots.sql @@ -1,4 +1,21 @@ {% macro instances_should_be_configured_to_copy_tags_to_snapshots(framework, check_id) %} + {{ return(adapter.dispatch('instances_should_be_configured_to_copy_tags_to_snapshots')(framework, check_id)) }} +{% endmacro %} + +{% macro default__instances_should_be_configured_to_copy_tags_to_snapshots(framework, check_id) %}{% endmacro %} + +{% macro postgres__instances_should_be_configured_to_copy_tags_to_snapshots(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS DB instances should be configured to copy tags to snapshots' as title, + account_id, + arn AS resource_id, + case when copy_tags_to_snapshot != TRUE then 'fail' else 'pass' end as status +from aws_rds_instances +{% endmacro %} + +{% macro snowflake__instances_should_be_configured_to_copy_tags_to_snapshots(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/instances_should_be_configured_with_multiple_azs.sql b/transformations/aws/macros/rds/instances_should_be_configured_with_multiple_azs.sql index e5e6dc17b..f04bdadf3 100644 --- a/transformations/aws/macros/rds/instances_should_be_configured_with_multiple_azs.sql +++ b/transformations/aws/macros/rds/instances_should_be_configured_with_multiple_azs.sql @@ -1,4 +1,21 @@ {% macro instances_should_be_configured_with_multiple_azs(framework, check_id) %} + {{ return(adapter.dispatch('instances_should_be_configured_with_multiple_azs')(framework, check_id)) }} +{% endmacro %} + +{% macro default__instances_should_be_configured_with_multiple_azs(framework, check_id) %}{% endmacro %} + +{% macro postgres__instances_should_be_configured_with_multiple_azs(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS DB instances should be configured with multiple Availability Zones' as title, + account_id, + arn AS resource_id, + case when multi_az != TRUE then 'fail' else 'pass' end as status +from aws_rds_instances +{% endmacro %} + +{% macro snowflake__instances_should_be_configured_with_multiple_azs(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/instances_should_be_deployed_in_a_vpc.sql b/transformations/aws/macros/rds/instances_should_be_deployed_in_a_vpc.sql index 234de8b47..354eb83a2 100644 --- a/transformations/aws/macros/rds/instances_should_be_deployed_in_a_vpc.sql +++ b/transformations/aws/macros/rds/instances_should_be_deployed_in_a_vpc.sql @@ -1,4 +1,21 @@ {% macro instances_should_be_deployed_in_a_vpc(framework, check_id) %} + {{ return(adapter.dispatch('instances_should_be_deployed_in_a_vpc')(framework, check_id)) }} +{% endmacro %} + +{% macro default__instances_should_be_deployed_in_a_vpc(framework, check_id) %}{% endmacro %} + +{% macro postgres__instances_should_be_deployed_in_a_vpc(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS instances should be deployed in a VPC' as title, + account_id, + arn AS resource_id, + case when db_subnet_group ->> 'VpcId' is null then 'fail' else 'pass' end as status +from aws_rds_instances +{% endmacro %} + +{% macro snowflake__instances_should_be_deployed_in_a_vpc(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/instances_should_have_deletion_protection_enabled.sql b/transformations/aws/macros/rds/instances_should_have_deletion_protection_enabled.sql index d670367a9..24cfe5e7b 100644 --- a/transformations/aws/macros/rds/instances_should_have_deletion_protection_enabled.sql +++ b/transformations/aws/macros/rds/instances_should_have_deletion_protection_enabled.sql @@ -1,4 +1,21 @@ {% macro instances_should_have_deletion_protection_enabled(framework, check_id) %} + {{ return(adapter.dispatch('instances_should_have_deletion_protection_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__instances_should_have_deletion_protection_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__instances_should_have_deletion_protection_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS DB instances should have deletion protection enabled' as title, + account_id, + arn AS resource_id, + case when deletion_protection != TRUE then 'fail' else 'pass' end as status +from aws_rds_instances +{% endmacro %} + +{% macro snowflake__instances_should_have_deletion_protection_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/instances_should_have_ecnryption_at_rest_enabled.sql b/transformations/aws/macros/rds/instances_should_have_ecnryption_at_rest_enabled.sql index 5154ab5ce..d04a6a2b1 100644 --- a/transformations/aws/macros/rds/instances_should_have_ecnryption_at_rest_enabled.sql +++ b/transformations/aws/macros/rds/instances_should_have_ecnryption_at_rest_enabled.sql @@ -1,4 +1,21 @@ {% macro instances_should_have_ecnryption_at_rest_enabled(framework, check_id) %} + {{ return(adapter.dispatch('instances_should_have_ecnryption_at_rest_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__instances_should_have_ecnryption_at_rest_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__instances_should_have_ecnryption_at_rest_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS DB instances should have encryption at rest enabled' as title, + account_id, + arn AS resource_id, + case when storage_encrypted != TRUE then 'fail' else 'pass' end as status +from aws_rds_instances +{% endmacro %} + +{% macro snowflake__instances_should_have_ecnryption_at_rest_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/instances_should_prohibit_public_access.sql b/transformations/aws/macros/rds/instances_should_prohibit_public_access.sql index 486733ad1..af344320b 100644 --- a/transformations/aws/macros/rds/instances_should_prohibit_public_access.sql +++ b/transformations/aws/macros/rds/instances_should_prohibit_public_access.sql @@ -1,4 +1,21 @@ {% macro instances_should_prohibit_public_access(framework, check_id) %} + {{ return(adapter.dispatch('instances_should_prohibit_public_access')(framework, check_id)) }} +{% endmacro %} + +{% macro default__instances_should_prohibit_public_access(framework, check_id) %}{% endmacro %} + +{% macro postgres__instances_should_prohibit_public_access(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS DB instances should prohibit public access, determined by the PubliclyAccessible configuration' as title, + account_id, + arn AS resource_id, + case when publicly_accessible = TRUE then 'fail' else 'pass' end as status +from aws_rds_instances +{% endmacro %} + +{% macro snowflake__instances_should_prohibit_public_access(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/rds_cluster_default_admin_check.sql b/transformations/aws/macros/rds/rds_cluster_default_admin_check.sql index 5c70272e3..7bd9d28dc 100644 --- a/transformations/aws/macros/rds/rds_cluster_default_admin_check.sql +++ b/transformations/aws/macros/rds/rds_cluster_default_admin_check.sql @@ -1,4 +1,25 @@ {% macro rds_cluster_default_admin_check(framework, check_id) %} + {{ return(adapter.dispatch('rds_cluster_default_admin_check')(framework, check_id)) }} +{% endmacro %} + +{% macro default__rds_cluster_default_admin_check(framework, check_id) %}{% endmacro %} + +{% macro postgres__rds_cluster_default_admin_check(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS Database clusters should use a custom administrator username' as title, + account_id, + arn AS resource_id, + CASE + WHEN master_username NOT IN ('admin', 'root', 'administrator', 'master', 'sa', 'awsuser') THEN 'pass' + ELSE 'fail' + END AS status +FROM + aws_rds_clusters +{% endmacro %} + +{% macro snowflake__rds_cluster_default_admin_check(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/rds_cluster_encrypted_at_rest.sql b/transformations/aws/macros/rds/rds_cluster_encrypted_at_rest.sql index 19cf4b9bd..3a8e452eb 100644 --- a/transformations/aws/macros/rds/rds_cluster_encrypted_at_rest.sql +++ b/transformations/aws/macros/rds/rds_cluster_encrypted_at_rest.sql @@ -1,4 +1,25 @@ {% macro rds_cluster_encrypted_at_rest(framework, check_id) %} + {{ return(adapter.dispatch('rds_cluster_encrypted_at_rest')(framework, check_id)) }} +{% endmacro %} + +{% macro default__rds_cluster_encrypted_at_rest(framework, check_id) %}{% endmacro %} + +{% macro postgres__rds_cluster_encrypted_at_rest(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS DB clusters should be encrypted at rest' as title, + account_id, + arn AS resource_id, + CASE + WHEN storage_encrypted THEN 'pass' + ELSE 'fail' + END AS status +FROM + aws_rds_clusters +{% endmacro %} + +{% macro snowflake__rds_cluster_encrypted_at_rest(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/rds_cluster_event_notifications_configured.sql b/transformations/aws/macros/rds/rds_cluster_event_notifications_configured.sql index 38d9df0b1..b07897fa6 100644 --- a/transformations/aws/macros/rds/rds_cluster_event_notifications_configured.sql +++ b/transformations/aws/macros/rds/rds_cluster_event_notifications_configured.sql @@ -1,4 +1,29 @@ {% macro rds_cluster_event_notifications_configured(framework, check_id) %} + {{ return(adapter.dispatch('rds_cluster_event_notifications_configured')(framework, check_id)) }} +{% endmacro %} + +{% macro default__rds_cluster_event_notifications_configured(framework, check_id) %}{% endmacro %} + +{% macro postgres__rds_cluster_event_notifications_configured(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'An RDS event notifications subscription should be configured for critical cluster events' as title, + account_id, + SOURCE_ARN AS resource_id, + CASE + WHEN + 'maintenance' = any(EVENT_CATEGORIES) + AND 'failure' = any(EVENT_CATEGORIES) + THEN 'pass' + ELSE 'fail' + END AS status +FROM + aws_rds_events +WHERE source_type = 'db-cluster' +{% endmacro %} + +{% macro snowflake__rds_cluster_event_notifications_configured(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/rds_instance_default_admin_check.sql b/transformations/aws/macros/rds/rds_instance_default_admin_check.sql index aeeeba59d..80c241224 100644 --- a/transformations/aws/macros/rds/rds_instance_default_admin_check.sql +++ b/transformations/aws/macros/rds/rds_instance_default_admin_check.sql @@ -1,4 +1,25 @@ {% macro rds_instance_default_admin_check(framework, check_id) %} + {{ return(adapter.dispatch('rds_instance_default_admin_check')(framework, check_id)) }} +{% endmacro %} + +{% macro default__rds_instance_default_admin_check(framework, check_id) %}{% endmacro %} + +{% macro postgres__rds_instance_default_admin_check(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS database instances should use a custom administrator username' as title, + account_id, + arn AS resource_id, + CASE + WHEN master_username NOT IN ('admin', 'root', 'administrator', 'master', 'sa', 'awsuser') THEN 'pass' + ELSE 'fail' + END AS status +FROM + aws_rds_instances +{% endmacro %} + +{% macro snowflake__rds_instance_default_admin_check(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/rds_instance_event_notifications_configured.sql b/transformations/aws/macros/rds/rds_instance_event_notifications_configured.sql index 44e7bb29f..5015f2d5f 100644 --- a/transformations/aws/macros/rds/rds_instance_event_notifications_configured.sql +++ b/transformations/aws/macros/rds/rds_instance_event_notifications_configured.sql @@ -1,4 +1,31 @@ {% macro rds_instance_event_notifications_configured(framework, check_id) %} + {{ return(adapter.dispatch('rds_instance_event_notifications_configured')(framework, check_id)) }} +{% endmacro %} + +{% macro default__rds_instance_event_notifications_configured(framework, check_id) %}{% endmacro %} + +{% macro postgres__rds_instance_event_notifications_configured(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'An RDS event notifications subscription should be configured for critical database instance events' as title, + account_id, + SOURCE_ARN AS resource_id, + CASE + WHEN + 'maintenance' = any(EVENT_CATEGORIES) AND + 'configuration change' = any(EVENT_CATEGORIES) AND + 'failure' = any(EVENT_CATEGORIES) + THEN 'pass' + ELSE 'fail' + END AS status +FROM + aws_rds_events +WHERE + source_type = 'db-instance' +{% endmacro %} + +{% macro snowflake__rds_instance_event_notifications_configured(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/rds_pg_event_notifications_configured.sql b/transformations/aws/macros/rds/rds_pg_event_notifications_configured.sql index 0c1a42628..e70f9a8d1 100644 --- a/transformations/aws/macros/rds/rds_pg_event_notifications_configured.sql +++ b/transformations/aws/macros/rds/rds_pg_event_notifications_configured.sql @@ -1,4 +1,28 @@ {% macro rds_pg_event_notifications_configured(framework, check_id) %} + {{ return(adapter.dispatch('rds_pg_event_notifications_configured')(framework, check_id)) }} +{% endmacro %} + +{% macro default__rds_pg_event_notifications_configured(framework, check_id) %}{% endmacro %} + +{% macro postgres__rds_pg_event_notifications_configured(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'An RDS event notifications subscription should be configured for critical database parameter group events' as title, + account_id, + SOURCE_ARN AS resource_id, + CASE + WHEN + 'configuration change' = any(EVENT_CATEGORIES) + THEN 'pass' + ELSE 'fail' + END AS status +FROM + aws_rds_events +where source_type = 'db-parameter-group' +{% endmacro %} + +{% macro snowflake__rds_pg_event_notifications_configured(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/rds_sg_event_notifications_configured.sql b/transformations/aws/macros/rds/rds_sg_event_notifications_configured.sql index 9dd10b006..398349feb 100644 --- a/transformations/aws/macros/rds/rds_sg_event_notifications_configured.sql +++ b/transformations/aws/macros/rds/rds_sg_event_notifications_configured.sql @@ -1,4 +1,29 @@ {% macro rds_sg_event_notifications_configured(framework, check_id) %} + {{ return(adapter.dispatch('rds_sg_event_notifications_configured')(framework, check_id)) }} +{% endmacro %} + +{% macro default__rds_sg_event_notifications_configured(framework, check_id) %}{% endmacro %} + +{% macro postgres__rds_sg_event_notifications_configured(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'An RDS event notifications subscription should be configured for critical database security group events' as title, + account_id, + SOURCE_ARN AS resource_id, + CASE + WHEN + 'configuration change' = any(EVENT_CATEGORIES) AND + 'failure' = any(EVENT_CATEGORIES) + THEN 'pass' + ELSE 'fail' + END AS status +FROM + aws_rds_events +where source_type = 'db-security-group' +{% endmacro %} + +{% macro snowflake__rds_sg_event_notifications_configured(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/rds/rds_snapshots_public_prohibited.sql b/transformations/aws/macros/rds/rds_snapshots_public_prohibited.sql index 5614bdc36..fb574998b 100644 --- a/transformations/aws/macros/rds/rds_snapshots_public_prohibited.sql +++ b/transformations/aws/macros/rds/rds_snapshots_public_prohibited.sql @@ -1,4 +1,44 @@ {% macro rds_snapshots_public_prohibited(framework, check_id) %} + {{ return(adapter.dispatch('rds_snapshots_public_prohibited')(framework, check_id)) }} +{% endmacro %} + +{% macro default__rds_snapshots_public_prohibited(framework, check_id) %}{% endmacro %} + +{% macro postgres__rds_snapshots_public_prohibited(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS snapshot should be private' AS title, + account_id, + arn AS resource_id, + CASE + WHEN a ->> 'AttributeName' = 'restore' + AND a -> 'AttributeValues' ? 'all' + THEN 'fail' + ELSE 'pass' + END AS status +FROM + aws_rds_cluster_snapshots, + JSONB_ARRAY_ELEMENTS(ATTRIBUTES) AS a +UNION +SELECT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'RDS snapshot should be private' AS title, + account_id, + arn AS resource_id, + CASE + WHEN a ->> 'AttributeName' = 'restore' + AND a -> 'AttributeValues' ? 'all' + THEN 'fail' + ELSE 'pass' + END AS status +FROM + aws_rds_db_snapshots, + JSONB_ARRAY_ELEMENTS(ATTRIBUTES) AS a +{% endmacro %} + +{% macro snowflake__rds_snapshots_public_prohibited(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/redshift/redshift_cluster_kms_enabled.sql b/transformations/aws/macros/redshift/redshift_cluster_kms_enabled.sql index ad0d6f515..d7248e30d 100644 --- a/transformations/aws/macros/redshift/redshift_cluster_kms_enabled.sql +++ b/transformations/aws/macros/redshift/redshift_cluster_kms_enabled.sql @@ -1,4 +1,24 @@ {% macro redshift_cluster_kms_enabled(framework, check_id) %} + {{ return(adapter.dispatch('redshift_cluster_kms_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__redshift_cluster_kms_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__redshift_cluster_kms_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Redshift clusters should be encrypted at rest' as title, + account_id, + arn as resource_id, + CASE + WHEN encrypted AND kms_key_id is not null THEN 'pass' + ELSE 'fail' + END AS status +from aws_redshift_clusters +{% endmacro %} + +{% macro snowflake__redshift_cluster_kms_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/redshift/redshift_default_admin_check.sql b/transformations/aws/macros/redshift/redshift_default_admin_check.sql index 8b44176b7..544b84937 100644 --- a/transformations/aws/macros/redshift/redshift_default_admin_check.sql +++ b/transformations/aws/macros/redshift/redshift_default_admin_check.sql @@ -1,4 +1,24 @@ {% macro redshift_default_admin_check(framework, check_id) %} + {{ return(adapter.dispatch('redshift_default_admin_check')(framework, check_id)) }} +{% endmacro %} + +{% macro default__redshift_default_admin_check(framework, check_id) %}{% endmacro %} + +{% macro postgres__redshift_default_admin_check(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Amazon Redshift clusters should not use the default Admin username' as title, + account_id, + arn as resource_id, + CASE + WHEN master_username = 'awsuser' THEN 'fail' + ELSE 'pass' + END AS status +from aws_redshift_clusters +{% endmacro %} + +{% macro snowflake__redshift_default_admin_check(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/redshift/redshift_default_db_name_check.sql b/transformations/aws/macros/redshift/redshift_default_db_name_check.sql index 3ada36f9a..7f3f79a39 100644 --- a/transformations/aws/macros/redshift/redshift_default_db_name_check.sql +++ b/transformations/aws/macros/redshift/redshift_default_db_name_check.sql @@ -1,4 +1,24 @@ {% macro redshift_default_db_name_check(framework, check_id) %} + {{ return(adapter.dispatch('redshift_default_db_name_check')(framework, check_id)) }} +{% endmacro %} + +{% macro default__redshift_default_db_name_check(framework, check_id) %}{% endmacro %} + +{% macro postgres__redshift_default_db_name_check(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Redshift clusters should not use the default database name' as title, + account_id, + arn as resource_id, + CASE + WHEN db_name = 'dev' THEN 'fail' + ELSE 'pass' + END AS status +from aws_redshift_clusters +{% endmacro %} + +{% macro snowflake__redshift_default_db_name_check(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/s3/s3_bucket_default_lock_enabled.sql b/transformations/aws/macros/s3/s3_bucket_default_lock_enabled.sql index 6e3c25b8a..c011ff429 100644 --- a/transformations/aws/macros/s3/s3_bucket_default_lock_enabled.sql +++ b/transformations/aws/macros/s3/s3_bucket_default_lock_enabled.sql @@ -1,4 +1,30 @@ {% macro s3_bucket_default_lock_enabled(framework, check_id) %} + {{ return(adapter.dispatch('s3_bucket_default_lock_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__s3_bucket_default_lock_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__s3_bucket_default_lock_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'S3 buckets should be configured to use Object Lock' AS title, + a.account_id, + a.arn AS resource_id, + CASE WHEN b.object_lock_enabled = 'Enabled' THEN 'pass' ELSE 'fail' END AS status +FROM + aws_s3_buckets a +LEFT JOIN + aws_s3_bucket_object_lock_configurations b +ON + a.arn = b.bucket_arn +GROUP BY + a.account_id, + a.arn, + status +{% endmacro %} + +{% macro snowflake__s3_bucket_default_lock_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/s3/s3_bucket_level_public_access_prohibited.sql b/transformations/aws/macros/s3/s3_bucket_level_public_access_prohibited.sql index bf8380127..039ef047a 100644 --- a/transformations/aws/macros/s3/s3_bucket_level_public_access_prohibited.sql +++ b/transformations/aws/macros/s3/s3_bucket_level_public_access_prohibited.sql @@ -1,4 +1,31 @@ {% macro s3_bucket_level_public_access_prohibited(framework, check_id) %} + {{ return(adapter.dispatch('s3_bucket_level_public_access_prohibited')(framework, check_id)) }} +{% endmacro %} + +{% macro default__s3_bucket_level_public_access_prohibited(framework, check_id) %}{% endmacro %} + +{% macro postgres__s3_bucket_level_public_access_prohibited(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'S3 Block Public Access setting should be enabled at the bucket-level' AS title, + b.account_id, + b.arn AS resource_id, + CASE + when (pab.public_access_block_configuration -> 'block_public_acls')::boolean + and (pab.public_access_block_configuration -> 'block_public_policy')::boolean + and (pab.public_access_block_configuration -> 'ignore_public_acls')::boolean + and (pab.public_access_block_configuration -> 'restrict_public_buckets')::boolean + THEN 'pass' + ELSE 'fail' + END AS status +FROM + aws_s3_buckets as b +LEFT JOIN + aws_s3_bucket_public_access_blocks as pab on pab.bucket_arn = b.arn +{% endmacro %} + +{% macro snowflake__s3_bucket_level_public_access_prohibited(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/s3/s3_bucket_logging_enabled.sql b/transformations/aws/macros/s3/s3_bucket_logging_enabled.sql index d570b839b..7ee54d838 100644 --- a/transformations/aws/macros/s3/s3_bucket_logging_enabled.sql +++ b/transformations/aws/macros/s3/s3_bucket_logging_enabled.sql @@ -1,4 +1,27 @@ {% macro s3_bucket_logging_enabled(framework, check_id) %} + {{ return(adapter.dispatch('s3_bucket_logging_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__s3_bucket_logging_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__s3_bucket_logging_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'S3 bucket server access logging should be enabled' AS title, + b.account_id, + b.arn AS resource_id, + CASE + when bl.logging_enabled -> 'TargetBucket' IS NOT NULL + THEN 'pass' ELSE 'fail' + END AS status +FROM + aws_s3_buckets as b +LEFT JOIN + aws_s3_bucket_loggings as bl on bl.bucket_arn = b.arn +{% endmacro %} + +{% macro snowflake__s3_bucket_logging_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/s3/s3_event_notifications_enabled.sql b/transformations/aws/macros/s3/s3_event_notifications_enabled.sql index 695fc1e4c..fafd06b69 100644 --- a/transformations/aws/macros/s3/s3_event_notifications_enabled.sql +++ b/transformations/aws/macros/s3/s3_event_notifications_enabled.sql @@ -1,4 +1,29 @@ {% macro s3_event_notifications_enabled(framework, check_id) %} + {{ return(adapter.dispatch('s3_event_notifications_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__s3_event_notifications_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__s3_event_notifications_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'S3 buckets should have event notifications enabled' AS title, + account_id, + bucket_arn AS resource_id, + CASE WHEN + (EVENT_BRIDGE_CONFIGURATION::text IS NULL OR jsonb_array_length(EVENT_BRIDGE_CONFIGURATION) = 0) + AND (LAMBDA_FUNCTION_CONFIGURATIONS::text IS NULL OR jsonb_array_length(LAMBDA_FUNCTION_CONFIGURATIONS) = 0) + AND (QUEUE_CONFIGURATIONS::text IS NULL OR jsonb_array_length(QUEUE_CONFIGURATIONS) = 0) + AND (TOPIC_CONFIGURATIONS::text IS NULL OR jsonb_array_length(TOPIC_CONFIGURATIONS) = 0) + THEN 'fail' + ELSE 'pass' + END AS status +FROM + aws_s3_bucket_notification_configurations +{% endmacro %} + +{% macro snowflake__s3_event_notifications_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/s3/s3_lifecycle_policy_check.sql b/transformations/aws/macros/s3/s3_lifecycle_policy_check.sql index 2fe4415df..6e8e47b12 100644 --- a/transformations/aws/macros/s3/s3_lifecycle_policy_check.sql +++ b/transformations/aws/macros/s3/s3_lifecycle_policy_check.sql @@ -1,4 +1,29 @@ {% macro s3_lifecycle_policy_check(framework, check_id) %} + {{ return(adapter.dispatch('s3_lifecycle_policy_check')(framework, check_id)) }} +{% endmacro %} + +{% macro default__s3_lifecycle_policy_check(framework, check_id) %}{% endmacro %} + +{% macro postgres__s3_lifecycle_policy_check(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'S3 buckets should have lifecycle policies configured' AS title, + b.account_id, + b.arn AS resource_id, + CASE + WHEN l.STATUS = 'Enabled' THEN 'pass' + ELSE 'fail' + END AS status +FROM + aws_s3_buckets AS b +LEFT JOIN + aws_s3_bucket_lifecycles AS l +ON + b.arn = l.bucket_arn +{% endmacro %} + +{% macro snowflake__s3_lifecycle_policy_check(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/s3/s3_version_lifecycle_policy_check.sql b/transformations/aws/macros/s3/s3_version_lifecycle_policy_check.sql index f3aa24bb3..08b9007a7 100644 --- a/transformations/aws/macros/s3/s3_version_lifecycle_policy_check.sql +++ b/transformations/aws/macros/s3/s3_version_lifecycle_policy_check.sql @@ -1,4 +1,34 @@ {% macro s3_version_lifecycle_policy_check(framework, check_id) %} + {{ return(adapter.dispatch('s3_version_lifecycle_policy_check')(framework, check_id)) }} +{% endmacro %} + +{% macro default__s3_version_lifecycle_policy_check(framework, check_id) %}{% endmacro %} + +{% macro postgres__s3_version_lifecycle_policy_check(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'S3 buckets with versioning enabled should have lifecycle policies configured' AS title, + b.account_id, + b.arn AS resource_id, + CASE + WHEN l.STATUS = 'Enabled' THEN 'pass' + ELSE 'fail' + END AS status +FROM + aws_s3_buckets AS b +LEFT JOIN + aws_s3_bucket_versionings AS bv + ON + b.arn = bv.bucket_arn +LEFT JOIN + aws_s3_bucket_lifecycles AS l + ON + b.arn = l.bucket_arn +where bv.status = 'Enabled' +{% endmacro %} + +{% macro snowflake__s3_version_lifecycle_policy_check(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/sagemaker/sagemaker_notebook_instance_inside_vpc.sql b/transformations/aws/macros/sagemaker/sagemaker_notebook_instance_inside_vpc.sql index eb9ae6a96..5b7b1de4e 100644 --- a/transformations/aws/macros/sagemaker/sagemaker_notebook_instance_inside_vpc.sql +++ b/transformations/aws/macros/sagemaker/sagemaker_notebook_instance_inside_vpc.sql @@ -1,4 +1,23 @@ {% macro sagemaker_notebook_instance_inside_vpc(framework, check_id) %} + {{ return(adapter.dispatch('sagemaker_notebook_instance_inside_vpc')(framework, check_id)) }} +{% endmacro %} + +{% macro default__sagemaker_notebook_instance_inside_vpc(framework, check_id) %}{% endmacro %} + +{% macro postgres__sagemaker_notebook_instance_inside_vpc(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'SageMaker notebook instances should be launched in a custom VPC' as title, + account_id, + arn as resource_id, + case when + subnet_id is not null + then 'pass' else 'fail' end as status +from aws_sagemaker_notebook_instances +{% endmacro %} + +{% macro snowflake__sagemaker_notebook_instance_inside_vpc(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/sagemaker/sagemaker_notebook_instance_root_access_check.sql b/transformations/aws/macros/sagemaker/sagemaker_notebook_instance_root_access_check.sql index 13e912b3a..4cf011704 100644 --- a/transformations/aws/macros/sagemaker/sagemaker_notebook_instance_root_access_check.sql +++ b/transformations/aws/macros/sagemaker/sagemaker_notebook_instance_root_access_check.sql @@ -1,4 +1,23 @@ {% macro sagemaker_notebook_instance_root_access_check(framework, check_id) %} + {{ return(adapter.dispatch('sagemaker_notebook_instance_root_access_check')(framework, check_id)) }} +{% endmacro %} + +{% macro default__sagemaker_notebook_instance_root_access_check(framework, check_id) %}{% endmacro %} + +{% macro postgres__sagemaker_notebook_instance_root_access_check(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Users should not have root access to SageMaker notebook instances' as title, + account_id, + arn as resource_id, + case when + root_access = 'Disabled' + then 'pass' else 'fail' end as status +from aws_sagemaker_notebook_instances +{% endmacro %} + +{% macro snowflake__sagemaker_notebook_instance_root_access_check(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/stepfunctions/step_functions_state_machine_logging_enabled.sql b/transformations/aws/macros/stepfunctions/step_functions_state_machine_logging_enabled.sql index 34f7d0142..65f9980e9 100644 --- a/transformations/aws/macros/stepfunctions/step_functions_state_machine_logging_enabled.sql +++ b/transformations/aws/macros/stepfunctions/step_functions_state_machine_logging_enabled.sql @@ -1,4 +1,26 @@ {% macro step_functions_state_machine_logging_enabled(framework, check_id) %} + {{ return(adapter.dispatch('step_functions_state_machine_logging_enabled')(framework, check_id)) }} +{% endmacro %} + +{% macro default__step_functions_state_machine_logging_enabled(framework, check_id) %}{% endmacro %} + +{% macro postgres__step_functions_state_machine_logging_enabled(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'Step Functions state machines should have logging turned on' as title, + account_id, + arn as resource_id, + case when + LOGGING_CONFIGURATION ->> 'Level' is null or LOGGING_CONFIGURATION ->> 'Level' = 'OFF' + or (LOGGING_CONFIGURATION ->> 'Level' != 'OFF' and LOGGING_CONFIGURATION ->> 'destinations' is null) then 'fail' + else 'pass' + end as status +from + aws_stepfunctions_state_machines +{% endmacro %} + +{% macro snowflake__step_functions_state_machine_logging_enabled(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/waf/waf_global_rule_not_empty.sql b/transformations/aws/macros/waf/waf_global_rule_not_empty.sql index ffc49b117..7339e7468 100644 --- a/transformations/aws/macros/waf/waf_global_rule_not_empty.sql +++ b/transformations/aws/macros/waf/waf_global_rule_not_empty.sql @@ -1,4 +1,27 @@ {% macro waf_global_rule_not_empty(framework, check_id) %} + {{ return(adapter.dispatch('waf_global_rule_not_empty')(framework, check_id)) }} +{% endmacro %} + +{% macro default__waf_global_rule_not_empty(framework, check_id) %}{% endmacro %} + +{% macro postgres__waf_global_rule_not_empty(framework, check_id) %} +SELECT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'A WAF global rule should have at least one condition' as title, + account_id, + arn as resource_id, + case + WHEN + predicates is null + or jsonb_array_length(predicates) = 0 then 'fail' + else 'pass' + end as status +from + aws_waf_rules +{% endmacro %} + +{% macro snowflake__waf_global_rule_not_empty(framework, check_id) %} SELECT '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/waf/waf_global_rulegroup_not_empty.sql b/transformations/aws/macros/waf/waf_global_rulegroup_not_empty.sql index faf9bdeb8..ef12b98d1 100644 --- a/transformations/aws/macros/waf/waf_global_rulegroup_not_empty.sql +++ b/transformations/aws/macros/waf/waf_global_rulegroup_not_empty.sql @@ -1,4 +1,26 @@ {% macro waf_global_rulegroup_not_empty(framework, check_id) %} + {{ return(adapter.dispatch('waf_global_rulegroup_not_empty')(framework, check_id)) }} +{% endmacro %} + +{% macro default__waf_global_rulegroup_not_empty(framework, check_id) %}{% endmacro %} + +{% macro postgres__waf_global_rulegroup_not_empty(framework, check_id) %} +SELECT + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'A WAF global rule group should have at least one rule' as title, + account_id, + arn as resource_id, + case + WHEN + rule_ids is null then 'fail' + else 'pass' + end as status +from + aws_waf_rule_groups +{% endmacro %} + +{% macro snowflake__waf_global_rulegroup_not_empty(framework, check_id) %} SELECT '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/waf/waf_global_webacl_not_empty.sql b/transformations/aws/macros/waf/waf_global_webacl_not_empty.sql index 3da84eb0d..ef47fe241 100644 --- a/transformations/aws/macros/waf/waf_global_webacl_not_empty.sql +++ b/transformations/aws/macros/waf/waf_global_webacl_not_empty.sql @@ -1,4 +1,26 @@ {% macro waf_global_webacl_not_empty(framework, check_id) %} + {{ return(adapter.dispatch('waf_global_webacl_not_empty')(framework, check_id)) }} +{% endmacro %} + +{% macro default__waf_global_webacl_not_empty(framework, check_id) %}{% endmacro %} + +{% macro postgres__waf_global_webacl_not_empty(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'A WAF global web ACL should have at least one rule or rule group' as title, + account_id, + arn, + CASE + WHEN + jsonb_array_length(rules) = 0 THEN 'fail' + ELSE 'pass' + END AS rule_status +FROM + aws_waf_web_acls +{% endmacro %} + +{% macro snowflake__waf_global_webacl_not_empty(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/waf/waf_regional_rule_not_empty.sql b/transformations/aws/macros/waf/waf_regional_rule_not_empty.sql index 027c06903..b3a081202 100644 --- a/transformations/aws/macros/waf/waf_regional_rule_not_empty.sql +++ b/transformations/aws/macros/waf/waf_regional_rule_not_empty.sql @@ -1,4 +1,27 @@ {% macro waf_regional_rule_not_empty(framework, check_id) %} + {{ return(adapter.dispatch('waf_regional_rule_not_empty')(framework, check_id)) }} +{% endmacro %} + +{% macro default__waf_regional_rule_not_empty(framework, check_id) %}{% endmacro %} + +{% macro postgres__waf_regional_rule_not_empty(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'A WAF Regional rule should have at least one condition' as title, + account_id, + arn as resource_id, + case + WHEN + predicates is null + or jsonb_array_length(predicates) = 0 then 'fail' + else 'pass' + end as status +from + aws_wafregional_rules +{% endmacro %} + +{% macro snowflake__waf_regional_rule_not_empty(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/waf/waf_regional_rulegroup_not_empty.sql b/transformations/aws/macros/waf/waf_regional_rulegroup_not_empty.sql index 8d10bbbfd..fdf45bdb4 100644 --- a/transformations/aws/macros/waf/waf_regional_rulegroup_not_empty.sql +++ b/transformations/aws/macros/waf/waf_regional_rulegroup_not_empty.sql @@ -1,4 +1,26 @@ {% macro waf_regional_rulegroup_not_empty(framework, check_id) %} + {{ return(adapter.dispatch('waf_regional_rulegroup_not_empty')(framework, check_id)) }} +{% endmacro %} + +{% macro default__waf_regional_rulegroup_not_empty(framework, check_id) %}{% endmacro %} + +{% macro postgres__waf_regional_rulegroup_not_empty(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'A WAF Regional rule group should have at least one rule' as title, + account_id, + arn as resource_id, + case + WHEN + rule_ids is null then 'fail' + else 'pass' + end as status +from + aws_wafregional_rule_groups +{% endmacro %} + +{% macro snowflake__waf_regional_rulegroup_not_empty(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/waf/waf_regional_webacl_not_empty.sql b/transformations/aws/macros/waf/waf_regional_webacl_not_empty.sql index 396e0424a..735a94a39 100644 --- a/transformations/aws/macros/waf/waf_regional_webacl_not_empty.sql +++ b/transformations/aws/macros/waf/waf_regional_webacl_not_empty.sql @@ -1,4 +1,25 @@ {% macro waf_regional_webacl_not_empty(framework, check_id) %} + {{ return(adapter.dispatch('waf_regional_webacl_not_empty')(framework, check_id)) }} +{% endmacro %} + +{% macro default__waf_regional_webacl_not_empty(framework, check_id) %}{% endmacro %} + +{% macro postgres__waf_regional_webacl_not_empty(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'A WAF Regional web ACL should have at least one rule or rule group' as title, + account_id, + arn as resource_id, + case + WHEN jsonb_array_length(rules) = 0 THEN 'fail' + else 'pass' + end as status +from + aws_wafregional_web_acls +{% endmacro %} + +{% macro snowflake__waf_regional_webacl_not_empty(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id, diff --git a/transformations/aws/macros/waf/wafv2_webacl_not_empty.sql b/transformations/aws/macros/waf/wafv2_webacl_not_empty.sql index 7e4018947..b26add079 100644 --- a/transformations/aws/macros/waf/wafv2_webacl_not_empty.sql +++ b/transformations/aws/macros/waf/wafv2_webacl_not_empty.sql @@ -1,4 +1,25 @@ {% macro wafv2_webacl_not_empty(framework, check_id) %} + {{ return(adapter.dispatch('wafv2_webacl_not_empty')(framework, check_id)) }} +{% endmacro %} + +{% macro default__wafv2_webacl_not_empty(framework, check_id) %}{% endmacro %} + +{% macro postgres__wafv2_webacl_not_empty(framework, check_id) %} +select + '{{framework}}' As framework, + '{{check_id}}' As check_id, + 'A WAFv2 web ACL should have at least one rule or rule group' as title, + account_id, + arn, + CASE + WHEN jsonb_array_length(rules) > 0 or jsonb_array_length(POST_PROCESS_FIREWALL_MANAGER_RULE_GROUPS) > 0 or jsonb_array_length(PRE_PROCESS_FIREWALL_MANAGER_RULE_GROUPS) > 0 THEN 'pass' + ELSE 'fail' + END AS rule_status +FROM + aws_wafv2_web_acls +{% endmacro %} + +{% macro snowflake__wafv2_webacl_not_empty(framework, check_id) %} select '{{framework}}' As framework, '{{check_id}}' As check_id,