From 8a2cb9247dac084449f3fe293c670e633f309e22 Mon Sep 17 00:00:00 2001 From: Kemal <223029+disq@users.noreply.github.com> Date: Mon, 18 Jul 2022 14:10:40 +0100 Subject: [PATCH] feat: Policies (#1220) * feat: Policies * Add policies.go * Ref to create * Fix embed pattern * Try to run a test * psql: Use password * Remove go:embed * Two step policy run * policy test: Generate tables without cq binary * Run the correct file * remove sql dir Co-authored-by: Kemal Hadimli --- .github/workflows/test_policy_sql.yml | 70 ++++++ policies/README.md | 32 +++ policies/cis_v1.2.0/policy.sql | 7 + policies/cis_v1.2.0/section_1.sql | 46 ++++ policies/cis_v1.2.0/section_2.sql | 22 ++ policies/cis_v1.2.0/section_3.sql | 42 ++++ policies/cis_v1.2.0/section_4.sql | 12 + policies/create_aws_policy_results.sql | 9 + policies/foundational_security/acm.sql | 3 + policies/foundational_security/apigateway.sql | 22 ++ .../foundational_security/autoscaling.sql | 3 + policies/foundational_security/awsconfig.sql | 3 + policies/foundational_security/cloudfront.sql | 23 ++ policies/foundational_security/cloudtrail.sql | 15 ++ policies/foundational_security/codebuild.sql | 7 + policies/foundational_security/dms.sql | 3 + policies/foundational_security/dynamodb.sql | 11 + policies/foundational_security/ec2.sql | 59 +++++ policies/foundational_security/ecs.sql | 7 + policies/foundational_security/efs.sql | 7 + .../elastic_beanstalk.sql | 7 + .../foundational_security/elasticsearch.sql | 31 +++ policies/foundational_security/elb.sql | 27 +++ policies/foundational_security/elbv2.sql | 3 + policies/foundational_security/emr.sql | 3 + policies/foundational_security/guardduty.sql | 3 + policies/foundational_security/iam.sql | 35 +++ policies/foundational_security/kms.sql | 11 + policies/foundational_security/lambda.sql | 7 + policies/foundational_security/policy.sql | 33 +++ policies/foundational_security/rds.sql | 87 ++++++++ policies/foundational_security/redshift.sql | 23 ++ policies/foundational_security/s3.sql | 27 +++ policies/foundational_security/sagemaker.sql | 3 + .../foundational_security/secretmanager.sql | 15 ++ policies/foundational_security/sns.sql | 3 + policies/foundational_security/sqs.sql | 3 + policies/foundational_security/ssm.sql | 15 ++ policies/foundational_security/waf.sql | 3 + policies/pci_dss_v3.2.1/policy.sql | 206 ++++++++++++++++++ policies/policy.sql | 6 + policies/public_egress/policy.sql | 18 ++ policies/publicly_available/policy.sql | 35 +++ .../acm/certificates_should_be_renewed.sql | 14 ++ .../apigateway/api_gw_associated_with_waf.sql | 14 ++ .../apigateway/api_gw_cache_encrypted.sql | 18 ++ .../api_gw_execution_logging_enabled.sql | 36 +++ .../apigateway/api_gw_publicly_accessible.sql | 14 ++ .../queries/apigateway/api_gw_ssl_enabled.sql | 14 ++ .../api_gw_v2_publicly_accessible.sql | 11 + .../apigateway/api_gw_xray_enabled.sql | 14 ++ .../autoscaling_groups_elb_check.sql | 14 ++ .../cloudfront/access_logs_enabled.sql | 13 ++ .../queries/cloudfront/all_distributions.sql | 11 + .../cloudfront/associated_with_waf.sql | 13 ++ .../default_root_object_configured.sql | 13 ++ .../origin_access_identity_enabled.sql | 14 ++ .../cloudfront/origin_failover_enabled.sql | 14 ++ .../cloudfront/viewer_policy_https.sql | 20 ++ ...ail-trail-logs-encrypted-with-kms-keys.sql | 12 + .../cloudtrail/bucket_access_logging.sql | 14 ++ .../cloudtrail/enabled_in_all_regions.sql | 19 ++ .../integrated_with_cloudwatch_logs.sql | 15 ++ .../log_file_validation_enabled.sql | 13 ++ .../queries/cloudtrail/logs_encrypted.sql | 13 ++ .../cloudwatch/alarm_aws_config_changes.sql | 14 ++ .../alarm_cloudtrail_config_changes.sql | 17 ++ .../cloudwatch/alarm_console_auth_failure.sql | 14 ++ .../cloudwatch/alarm_console_no_mfa.sql | 14 ++ .../cloudwatch/alarm_delete_customer_cmk.sql | 15 ++ .../cloudwatch/alarm_iam_policy_change.sql | 28 +++ .../queries/cloudwatch/alarm_nacl_changes.sql | 18 ++ .../cloudwatch/alarm_network_gateways.sql | 18 ++ .../queries/cloudwatch/alarm_root_account.sql | 15 ++ .../cloudwatch/alarm_route_table_changes.sql | 19 ++ .../alarm_s3_bucket_policy_change.sql | 22 ++ .../alarm_security_group_changes.sql | 18 ++ .../cloudwatch/alarm_unauthorized_api.sql | 14 ++ .../queries/cloudwatch/alarm_vpc_changes.sql | 24 ++ .../codebuild/check_environment_variables.sql | 25 +++ .../check_oauth_usage_for_sources.sql | 16 ++ .../queries/config/enabled_all_regions.sql | 18 ++ .../queries/dms/replication_not_public.sql | 14 ++ .../dynamodb/autoscale_or_ondemand.sql | 32 +++ .../dynamodb/dax_encrypted_at_rest.sql | 14 ++ .../dynamodb/point_in_time_recovery.sql | 15 ++ policies/queries/ec2/default_sg_no_access.sql | 19 ++ .../ebs_encryption_by_default_disabled.sql | 14 ++ .../ec2/ebs_snapshot_permissions_check.sql | 25 +++ .../ec2/flow_logs_enabled_in_all_vpcs.sql | 16 ++ .../queries/ec2/get_unused_public_ips.sql | 14 ++ ...es_with_more_than_2_network_interfaces.sql | 20 ++ .../queries/ec2/instances_with_public_ip.sql | 14 ++ .../no_broad_public_ingress_on_port_22.sql | 18 ++ .../no_broad_public_ingress_on_port_3389.sql | 18 ++ .../queries/ec2/no_unsued_security_groups.sql | 14 ++ policies/queries/ec2/not_imdsv2_instances.sql | 14 ++ ...public_egress_sg_and_routing_instances.sql | 30 +++ .../ec2/public_egress_sg_instances.sql | 17 ++ policies/queries/ec2/public_ips.sql | 11 + ...oups_with_access_to_unauthorized_ports.sql | 20 ++ ...curity_groups_with_open_critical_ports.sql | 40 ++++ .../queries/ec2/sgs_all_access_to_port_22.sql | 81 +++++++ ...opped_more_thant_30_days_ago_instances.sql | 16 ++ .../ec2/subnets_that_assign_public_ips.sql | 14 ++ .../queries/ec2/unencrypted_ebs_volumes.sql | 14 ++ policies/queries/ec2/unused_acls.sql | 17 ++ .../queries/ec2/vpcs_without_ec2_endpoint.sql | 25 +++ .../ecs/ecs_services_with_public_ips.sql | 15 ++ .../task_definitions_secure_networking.sql | 23 ++ .../efs_filesystems_with_disabled_backups.sql | 14 ++ .../efs/unencrypted_efs_filesystems.sql | 15 ++ .../advanced_health_reporting_enabled.sql | 15 ++ ...stic_beanstalk_managed_updates_enabled.sql | 24 ++ ...ains_should_be_encrypted_using_tls_1_2.sql | 14 ++ ...g_to_cloudwatch_logs_should_be_enabled.sql | 15 ++ ..._at_least_three_dedicated_master_nodes.sql | 16 ++ ...elasticsearch_domains_should_be_in_vpc.sql | 14 ++ ...should_encrypt_data_sent_between_nodes.sql | 14 ++ ..._should_have_at_least_three_data_nodes.sql | 16 ++ ...ains_should_have_audit_logging_enabled.sql | 15 ++ ...should_have_encryption_at_rest_enabled.sql | 14 ++ .../elb/alb_deletion_protection_enabled.sql | 17 ++ .../queries/elb/alb_drop_http_headers.sql | 17 ++ policies/queries/elb/alb_logging_enabled.sql | 34 +++ .../elb/elbv1_cert_provided_by_acm.sql | 20 ++ .../elb/elbv1_conn_draining_enabled.sql | 15 ++ policies/queries/elb/elbv1_https_or_tls.sql | 17 ++ .../elb/elbv1_https_predefined_policy.sql | 19 ++ .../queries/elb/elbv1_internet_facing.sql | 11 + .../queries/elb/elbv2_internet_facing.sql | 11 + .../elb/elbv2_redirect_http_to_https.sql | 18 ++ ...es_should_not_have_public_ip_addresses.sql | 14 ++ .../queries/guardduty/detector_enabled.sql | 35 +++ policies/queries/iam/avoid_root_usage.sql | 14 ++ .../iam/hardware_mfa_enabled_for_root.sql | 20 ++ ..._access_keys_rotated_more_than_90_days.sql | 15 ++ ...m_access_keys_unused_more_than_90_days.sql | 15 ++ .../iam/mfa_enabled_for_console_access.sql | 14 ++ policies/queries/iam/mfa_enabled_for_root.sql | 13 ++ policies/queries/iam/no_star.sql | 40 ++++ policies/queries/iam/old_access_keys.sql | 17 ++ .../password_policy_expire_old_passwords.sql | 15 ++ .../iam/password_policy_min_length.sql | 15 ++ .../iam/password_policy_min_lowercase.sql | 16 ++ .../iam/password_policy_min_number.sql | 16 ++ .../iam/password_policy_min_one_symbol.sql | 15 ++ .../iam/password_policy_min_uppercase.sql | 15 ++ .../iam/password_policy_prevent_reuse.sql | 16 ++ .../queries/iam/password_policy_strong.sql | 20 ++ .../iam/policies_attached_to_groups_roles.sql | 13 ++ .../iam/policies_with_admin_rights.sql | 45 ++++ .../queries/iam/root_user_no_access_keys.sql | 17 ++ .../queries/iam/unused_creds_disabled.sql | 18 ++ .../queries/iam/wildcard_access_policies.sql | 49 +++++ .../kms/cmk_not_scheduled_for_deletion.sql | 10 + .../customer_policy_blocked_kms_actions.sql | 44 ++++ .../kms/inline_policy_blocked_kms_actions.sql | 86 ++++++++ .../kms/rotation_enabled_for_customer_key.sql | 14 ++ .../lambda/functions_with_public_egress.sql | 47 ++++ .../queries/lambda/lambda_function_in_vpc.sql | 10 + ...lambda_function_prohibit_public_access.sql | 23 ++ ...unctions_should_use_supported_runtimes.sql | 13 ++ ...sters_should_have_backtracking_enabled.sql | 12 + .../database_logging_should_be_enabled.sql | 22 ++ ...ured_for_rds_db_instances_and_clusters.sql | 10 + ..._should_be_configured_for_rds_clusters.sql | 10 + ...should_be_configured_for_rds_instances.sql | 10 + ...nor_version_upgrades_should_be_enabled.sql | 10 + ..._snapshots_should_be_encrypted_at_rest.sql | 24 ++ ...hould_have_deletion_protection_enabled.sql | 10 + ...not_use_a_database_engine_default_port.sql | 34 +++ ...igured_for_multiple_availability_zones.sql | 10 + ...e_configured_to_copy_tags_to_snapshots.sql | 10 + ...e_configured_to_copy_tags_to_snapshots.sql | 10 + ...gured_with_multiple_availability_zones.sql | 10 + ...hould_have_deletion_protection_enabled.sql | 10 + ...should_have_encryption_at_rest_enabled.sql | 10 + ...nstances_should_prohibit_public_access.sql | 10 + ...configured_for_critical_cluster_events.sql | 53 +++++ ..._for_critical_database_instance_events.sql | 52 +++++ ...itical_database_parameter_group_events.sql | 53 +++++ ...ritical_database_security_group_events.sql | 53 +++++ ..._instances_should_be_deployed_in_a_vpc.sql | 10 + ...napshots_should_prohibit_public_access.sql | 13 ++ .../redshift/cluster_publicly_accessible.sql | 10 + ...lusters_should_be_encrypted_in_transit.sql | 28 +++ ...ters_should_have_audit_logging_enabled.sql | 16 ++ ...hould_have_automatic_snapshots_enabled.sql | 12 + ...tic_upgrades_to_major_versions_enabled.sql | 12 + ...usters_should_use_enhanced_vpc_routing.sql | 12 + .../s3/account_level_public_access_blocks.sql | 20 ++ .../s3/bucket_level_public_access_blocks.sql | 16 ++ policies/queries/s3/deny_http_requests.sql | 42 ++++ .../queries/s3/publicly_readable_buckets.sql | 72 ++++++ .../queries/s3/publicly_writable_buckets.sql | 72 ++++++ .../s3/restrict_cross_account_actions.sql | 56 +++++ .../s3/s3_cross_region_replication.sql | 16 ++ .../s3/s3_server_side_encryption_enabled.sql | 16 ++ ...stance_direct_internet_access_disabled.sql | 12 + .../remove_unused_secrets_manager_secrets.sql | 13 ++ ...ic_rotation_should_rotate_successfully.sql | 13 ++ ...ated_within_a_specified_number_of_days.sql | 13 ++ ...should_have_automatic_rotation_enabled.sql | 12 + ...uld_be_encrypted_at_rest_using_aws_kms.sql | 12 + ...uld_be_encrypted_at_rest_using_aws_kms.sql | 12 + .../ssm/documents_should_not_be_public.sql | 13 ++ ...ec2_instances_should_be_managed_by_ssm.sql | 14 ++ ...ciation_compliance_status_of_compliant.sql | 15 ++ ...e_patch_compliance_status_of_compliant.sql | 15 ++ .../waf_web_acl_logging_should_be_enabled.sql | 13 ++ ...afv2_web_acl_logging_should_be_enabled.sql | 30 +++ .../views/api_gateway_method_settings.sql | 23 ++ .../views/log_metric_filter_and_alarm.sql | 32 +++ .../views/security_group_egress_rules.sql | 26 +++ .../views/security_group_ingress_rules.sql | 26 +++ test/gen-tables.go | 26 +++ test/policy_cq_config.hcl | 23 -- 218 files changed, 4478 insertions(+), 23 deletions(-) create mode 100644 .github/workflows/test_policy_sql.yml create mode 100644 policies/README.md create mode 100644 policies/cis_v1.2.0/policy.sql create mode 100644 policies/cis_v1.2.0/section_1.sql create mode 100644 policies/cis_v1.2.0/section_2.sql create mode 100644 policies/cis_v1.2.0/section_3.sql create mode 100644 policies/cis_v1.2.0/section_4.sql create mode 100644 policies/create_aws_policy_results.sql create mode 100644 policies/foundational_security/acm.sql create mode 100644 policies/foundational_security/apigateway.sql create mode 100644 policies/foundational_security/autoscaling.sql create mode 100644 policies/foundational_security/awsconfig.sql create mode 100644 policies/foundational_security/cloudfront.sql create mode 100644 policies/foundational_security/cloudtrail.sql create mode 100644 policies/foundational_security/codebuild.sql create mode 100644 policies/foundational_security/dms.sql create mode 100644 policies/foundational_security/dynamodb.sql create mode 100644 policies/foundational_security/ec2.sql create mode 100644 policies/foundational_security/ecs.sql create mode 100644 policies/foundational_security/efs.sql create mode 100644 policies/foundational_security/elastic_beanstalk.sql create mode 100644 policies/foundational_security/elasticsearch.sql create mode 100644 policies/foundational_security/elb.sql create mode 100644 policies/foundational_security/elbv2.sql create mode 100644 policies/foundational_security/emr.sql create mode 100644 policies/foundational_security/guardduty.sql create mode 100644 policies/foundational_security/iam.sql create mode 100644 policies/foundational_security/kms.sql create mode 100644 policies/foundational_security/lambda.sql create mode 100644 policies/foundational_security/policy.sql create mode 100644 policies/foundational_security/rds.sql create mode 100644 policies/foundational_security/redshift.sql create mode 100644 policies/foundational_security/s3.sql create mode 100644 policies/foundational_security/sagemaker.sql create mode 100644 policies/foundational_security/secretmanager.sql create mode 100644 policies/foundational_security/sns.sql create mode 100644 policies/foundational_security/sqs.sql create mode 100644 policies/foundational_security/ssm.sql create mode 100644 policies/foundational_security/waf.sql create mode 100644 policies/pci_dss_v3.2.1/policy.sql create mode 100644 policies/policy.sql create mode 100644 policies/public_egress/policy.sql create mode 100644 policies/publicly_available/policy.sql create mode 100644 policies/queries/acm/certificates_should_be_renewed.sql create mode 100644 policies/queries/apigateway/api_gw_associated_with_waf.sql create mode 100644 policies/queries/apigateway/api_gw_cache_encrypted.sql create mode 100644 policies/queries/apigateway/api_gw_execution_logging_enabled.sql create mode 100644 policies/queries/apigateway/api_gw_publicly_accessible.sql create mode 100644 policies/queries/apigateway/api_gw_ssl_enabled.sql create mode 100644 policies/queries/apigateway/api_gw_v2_publicly_accessible.sql create mode 100644 policies/queries/apigateway/api_gw_xray_enabled.sql create mode 100644 policies/queries/autoscaling/autoscaling_groups_elb_check.sql create mode 100644 policies/queries/cloudfront/access_logs_enabled.sql create mode 100644 policies/queries/cloudfront/all_distributions.sql create mode 100644 policies/queries/cloudfront/associated_with_waf.sql create mode 100644 policies/queries/cloudfront/default_root_object_configured.sql create mode 100644 policies/queries/cloudfront/origin_access_identity_enabled.sql create mode 100644 policies/queries/cloudfront/origin_failover_enabled.sql create mode 100644 policies/queries/cloudfront/viewer_policy_https.sql create mode 100644 policies/queries/cloudtrail-trail-logs-encrypted-with-kms-keys.sql create mode 100644 policies/queries/cloudtrail/bucket_access_logging.sql create mode 100644 policies/queries/cloudtrail/enabled_in_all_regions.sql create mode 100644 policies/queries/cloudtrail/integrated_with_cloudwatch_logs.sql create mode 100644 policies/queries/cloudtrail/log_file_validation_enabled.sql create mode 100644 policies/queries/cloudtrail/logs_encrypted.sql create mode 100644 policies/queries/cloudwatch/alarm_aws_config_changes.sql create mode 100644 policies/queries/cloudwatch/alarm_cloudtrail_config_changes.sql create mode 100644 policies/queries/cloudwatch/alarm_console_auth_failure.sql create mode 100644 policies/queries/cloudwatch/alarm_console_no_mfa.sql create mode 100644 policies/queries/cloudwatch/alarm_delete_customer_cmk.sql create mode 100644 policies/queries/cloudwatch/alarm_iam_policy_change.sql create mode 100644 policies/queries/cloudwatch/alarm_nacl_changes.sql create mode 100644 policies/queries/cloudwatch/alarm_network_gateways.sql create mode 100644 policies/queries/cloudwatch/alarm_root_account.sql create mode 100644 policies/queries/cloudwatch/alarm_route_table_changes.sql create mode 100644 policies/queries/cloudwatch/alarm_s3_bucket_policy_change.sql create mode 100644 policies/queries/cloudwatch/alarm_security_group_changes.sql create mode 100644 policies/queries/cloudwatch/alarm_unauthorized_api.sql create mode 100644 policies/queries/cloudwatch/alarm_vpc_changes.sql create mode 100644 policies/queries/codebuild/check_environment_variables.sql create mode 100644 policies/queries/codebuild/check_oauth_usage_for_sources.sql create mode 100644 policies/queries/config/enabled_all_regions.sql create mode 100644 policies/queries/dms/replication_not_public.sql create mode 100644 policies/queries/dynamodb/autoscale_or_ondemand.sql create mode 100644 policies/queries/dynamodb/dax_encrypted_at_rest.sql create mode 100644 policies/queries/dynamodb/point_in_time_recovery.sql create mode 100644 policies/queries/ec2/default_sg_no_access.sql create mode 100644 policies/queries/ec2/ebs_encryption_by_default_disabled.sql create mode 100644 policies/queries/ec2/ebs_snapshot_permissions_check.sql create mode 100644 policies/queries/ec2/flow_logs_enabled_in_all_vpcs.sql create mode 100644 policies/queries/ec2/get_unused_public_ips.sql create mode 100644 policies/queries/ec2/instances_with_more_than_2_network_interfaces.sql create mode 100644 policies/queries/ec2/instances_with_public_ip.sql create mode 100644 policies/queries/ec2/no_broad_public_ingress_on_port_22.sql create mode 100644 policies/queries/ec2/no_broad_public_ingress_on_port_3389.sql create mode 100644 policies/queries/ec2/no_unsued_security_groups.sql create mode 100644 policies/queries/ec2/not_imdsv2_instances.sql create mode 100644 policies/queries/ec2/public_egress_sg_and_routing_instances.sql create mode 100644 policies/queries/ec2/public_egress_sg_instances.sql create mode 100644 policies/queries/ec2/public_ips.sql create mode 100644 policies/queries/ec2/security_groups_with_access_to_unauthorized_ports.sql create mode 100644 policies/queries/ec2/security_groups_with_open_critical_ports.sql create mode 100644 policies/queries/ec2/sgs_all_access_to_port_22.sql create mode 100644 policies/queries/ec2/stopped_more_thant_30_days_ago_instances.sql create mode 100644 policies/queries/ec2/subnets_that_assign_public_ips.sql create mode 100644 policies/queries/ec2/unencrypted_ebs_volumes.sql create mode 100644 policies/queries/ec2/unused_acls.sql create mode 100644 policies/queries/ec2/vpcs_without_ec2_endpoint.sql create mode 100644 policies/queries/ecs/ecs_services_with_public_ips.sql create mode 100644 policies/queries/ecs/task_definitions_secure_networking.sql create mode 100644 policies/queries/efs/efs_filesystems_with_disabled_backups.sql create mode 100644 policies/queries/efs/unencrypted_efs_filesystems.sql create mode 100644 policies/queries/elasticbeanstalk/advanced_health_reporting_enabled.sql create mode 100644 policies/queries/elasticbeanstalk/elastic_beanstalk_managed_updates_enabled.sql create mode 100644 policies/queries/elasticsearch/connections_to_elasticsearch_domains_should_be_encrypted_using_tls_1_2.sql create mode 100644 policies/queries/elasticsearch/elasticsearch_domain_error_logging_to_cloudwatch_logs_should_be_enabled.sql create mode 100644 policies/queries/elasticsearch/elasticsearch_domains_should_be_configured_with_at_least_three_dedicated_master_nodes.sql create mode 100644 policies/queries/elasticsearch/elasticsearch_domains_should_be_in_vpc.sql create mode 100644 policies/queries/elasticsearch/elasticsearch_domains_should_encrypt_data_sent_between_nodes.sql create mode 100644 policies/queries/elasticsearch/elasticsearch_domains_should_have_at_least_three_data_nodes.sql create mode 100644 policies/queries/elasticsearch/elasticsearch_domains_should_have_audit_logging_enabled.sql create mode 100644 policies/queries/elasticsearch/elasticsearch_domains_should_have_encryption_at_rest_enabled.sql create mode 100644 policies/queries/elb/alb_deletion_protection_enabled.sql create mode 100644 policies/queries/elb/alb_drop_http_headers.sql create mode 100644 policies/queries/elb/alb_logging_enabled.sql create mode 100644 policies/queries/elb/elbv1_cert_provided_by_acm.sql create mode 100644 policies/queries/elb/elbv1_conn_draining_enabled.sql create mode 100644 policies/queries/elb/elbv1_https_or_tls.sql create mode 100644 policies/queries/elb/elbv1_https_predefined_policy.sql create mode 100644 policies/queries/elb/elbv1_internet_facing.sql create mode 100644 policies/queries/elb/elbv2_internet_facing.sql create mode 100644 policies/queries/elb/elbv2_redirect_http_to_https.sql create mode 100644 policies/queries/emr/emr_cluster_master_nodes_should_not_have_public_ip_addresses.sql create mode 100644 policies/queries/guardduty/detector_enabled.sql create mode 100644 policies/queries/iam/avoid_root_usage.sql create mode 100644 policies/queries/iam/hardware_mfa_enabled_for_root.sql create mode 100644 policies/queries/iam/iam_access_keys_rotated_more_than_90_days.sql create mode 100644 policies/queries/iam/iam_access_keys_unused_more_than_90_days.sql create mode 100644 policies/queries/iam/mfa_enabled_for_console_access.sql create mode 100644 policies/queries/iam/mfa_enabled_for_root.sql create mode 100644 policies/queries/iam/no_star.sql create mode 100644 policies/queries/iam/old_access_keys.sql create mode 100644 policies/queries/iam/password_policy_expire_old_passwords.sql create mode 100644 policies/queries/iam/password_policy_min_length.sql create mode 100644 policies/queries/iam/password_policy_min_lowercase.sql create mode 100644 policies/queries/iam/password_policy_min_number.sql create mode 100644 policies/queries/iam/password_policy_min_one_symbol.sql create mode 100644 policies/queries/iam/password_policy_min_uppercase.sql create mode 100644 policies/queries/iam/password_policy_prevent_reuse.sql create mode 100644 policies/queries/iam/password_policy_strong.sql create mode 100644 policies/queries/iam/policies_attached_to_groups_roles.sql create mode 100644 policies/queries/iam/policies_with_admin_rights.sql create mode 100644 policies/queries/iam/root_user_no_access_keys.sql create mode 100644 policies/queries/iam/unused_creds_disabled.sql create mode 100644 policies/queries/iam/wildcard_access_policies.sql create mode 100644 policies/queries/kms/cmk_not_scheduled_for_deletion.sql create mode 100644 policies/queries/kms/customer_policy_blocked_kms_actions.sql create mode 100644 policies/queries/kms/inline_policy_blocked_kms_actions.sql create mode 100644 policies/queries/kms/rotation_enabled_for_customer_key.sql create mode 100644 policies/queries/lambda/functions_with_public_egress.sql create mode 100644 policies/queries/lambda/lambda_function_in_vpc.sql create mode 100644 policies/queries/lambda/lambda_function_prohibit_public_access.sql create mode 100644 policies/queries/lambda/lambda_functions_should_use_supported_runtimes.sql create mode 100644 policies/queries/rds/amazon_aurora_clusters_should_have_backtracking_enabled.sql create mode 100644 policies/queries/rds/database_logging_should_be_enabled.sql create mode 100644 policies/queries/rds/enhanced_monitoring_should_be_configured_for_rds_db_instances_and_clusters.sql create mode 100644 policies/queries/rds/iam_authentication_should_be_configured_for_rds_clusters.sql create mode 100644 policies/queries/rds/iam_authentication_should_be_configured_for_rds_instances.sql create mode 100644 policies/queries/rds/rds_automatic_minor_version_upgrades_should_be_enabled.sql create mode 100644 policies/queries/rds/rds_cluster_snapshots_and_database_snapshots_should_be_encrypted_at_rest.sql create mode 100644 policies/queries/rds/rds_clusters_should_have_deletion_protection_enabled.sql create mode 100644 policies/queries/rds/rds_databases_and_clusters_should_not_use_a_database_engine_default_port.sql create mode 100644 policies/queries/rds/rds_db_clusters_should_be_configured_for_multiple_availability_zones.sql create mode 100644 policies/queries/rds/rds_db_clusters_should_be_configured_to_copy_tags_to_snapshots.sql create mode 100644 policies/queries/rds/rds_db_instances_should_be_configured_to_copy_tags_to_snapshots.sql create mode 100644 policies/queries/rds/rds_db_instances_should_be_configured_with_multiple_availability_zones.sql create mode 100644 policies/queries/rds/rds_db_instances_should_have_deletion_protection_enabled.sql create mode 100644 policies/queries/rds/rds_db_instances_should_have_encryption_at_rest_enabled.sql create mode 100644 policies/queries/rds/rds_db_instances_should_prohibit_public_access.sql create mode 100644 policies/queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_cluster_events.sql create mode 100644 policies/queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_database_instance_events.sql create mode 100644 policies/queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_database_parameter_group_events.sql create mode 100644 policies/queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_database_security_group_events.sql create mode 100644 policies/queries/rds/rds_instances_should_be_deployed_in_a_vpc.sql create mode 100644 policies/queries/rds/snapshots_should_prohibit_public_access.sql create mode 100644 policies/queries/redshift/cluster_publicly_accessible.sql create mode 100644 policies/queries/redshift/clusters_should_be_encrypted_in_transit.sql create mode 100644 policies/queries/redshift/clusters_should_have_audit_logging_enabled.sql create mode 100644 policies/queries/redshift/clusters_should_have_automatic_snapshots_enabled.sql create mode 100644 policies/queries/redshift/clusters_should_have_automatic_upgrades_to_major_versions_enabled.sql create mode 100644 policies/queries/redshift/clusters_should_use_enhanced_vpc_routing.sql create mode 100644 policies/queries/s3/account_level_public_access_blocks.sql create mode 100644 policies/queries/s3/bucket_level_public_access_blocks.sql create mode 100644 policies/queries/s3/deny_http_requests.sql create mode 100644 policies/queries/s3/publicly_readable_buckets.sql create mode 100644 policies/queries/s3/publicly_writable_buckets.sql create mode 100644 policies/queries/s3/restrict_cross_account_actions.sql create mode 100644 policies/queries/s3/s3_cross_region_replication.sql create mode 100644 policies/queries/s3/s3_server_side_encryption_enabled.sql create mode 100644 policies/queries/sagemaker/sagemaker_notebook_instance_direct_internet_access_disabled.sql create mode 100644 policies/queries/secretsmanager/remove_unused_secrets_manager_secrets.sql create mode 100644 policies/queries/secretsmanager/secrets_configured_with_automatic_rotation_should_rotate_successfully.sql create mode 100644 policies/queries/secretsmanager/secrets_should_be_rotated_within_a_specified_number_of_days.sql create mode 100644 policies/queries/secretsmanager/secrets_should_have_automatic_rotation_enabled.sql create mode 100644 policies/queries/sns/sns_topics_should_be_encrypted_at_rest_using_aws_kms.sql create mode 100644 policies/queries/sqs/sqs_queues_should_be_encrypted_at_rest_using_aws_kms.sql create mode 100644 policies/queries/ssm/documents_should_not_be_public.sql create mode 100644 policies/queries/ssm/ec2_instances_should_be_managed_by_ssm.sql create mode 100644 policies/queries/ssm/instances_should_have_association_compliance_status_of_compliant.sql create mode 100644 policies/queries/ssm/instances_should_have_patch_compliance_status_of_compliant.sql create mode 100644 policies/queries/waf/waf_web_acl_logging_should_be_enabled.sql create mode 100644 policies/queries/wafv2/wafv2_web_acl_logging_should_be_enabled.sql create mode 100644 policies/views/api_gateway_method_settings.sql create mode 100644 policies/views/log_metric_filter_and_alarm.sql create mode 100644 policies/views/security_group_egress_rules.sql create mode 100644 policies/views/security_group_ingress_rules.sql create mode 100644 test/gen-tables.go delete mode 100644 test/policy_cq_config.hcl diff --git a/.github/workflows/test_policy_sql.yml b/.github/workflows/test_policy_sql.yml new file mode 100644 index 000000000..410dd7c8a --- /dev/null +++ b/.github/workflows/test_policy_sql.yml @@ -0,0 +1,70 @@ +name: SQL Policy Validation Test + +on: + push: + branches: + - main + pull_request: + branches: + - main + +env: + CGO_ENABLED: 0 + CQ_NO_TELEMETRY: 1 + PGPASSWORD: pass + +jobs: + SQLPolicyTest: + strategy: + matrix: + dbversion: [ "postgres:10" ] + go: [ "1.17" ] + platform: [ ubuntu-latest ] # can not run in macOS and widnowsOS + runs-on: ${{ matrix.platform }} + services: + postgres: + image: ${{ matrix.dbversion }} + env: + POSTGRES_PASSWORD: pass + POSTGRES_USER: postgres + POSTGRES_DB: postgres + ports: + - 5432:5432 + # Set health checks to wait until postgres has started + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: + - name: Check out code into the policy directory + uses: actions/checkout@v3 + + - name: Set up Go 1.x + uses: actions/setup-go@v3 + with: + go-version: ${{ matrix.go }} + + - uses: actions/cache@v3 + with: + # In order: + # * Module download cache + # * Build cache (Linux) + # * Build cache (Mac) + # * Build cache (Windows) + path: | + ~/go/pkg/mod + ~/.cache/go-build + ~/Library/Caches/go-build + ~\AppData\Local\go-build + key: ${{ runner.os }}-go-${{ matrix.go }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-${{ matrix.go }}- + + - name: Prepare for test - Create tables + run: | + go run ./test/gen-tables.go | psql -h localhost -p 5432 -U postgres -d postgres -w + + - name: Run all policies + run: | + cd policies && psql -h localhost -p 5432 -U postgres -d postgres -w -f ./policy.sql diff --git a/policies/README.md b/policies/README.md new file mode 100644 index 000000000..7d13f4868 --- /dev/null +++ b/policies/README.md @@ -0,0 +1,32 @@ +# CloudQuery Policies +CloudQuery SQL Policies for AWS + +## Policies and Compliance Frameworks Available + +- [AWS CIS V1.2.0](./cis_v1.2.0/policy.sql) +- [AWS PCI DSS v3.2.1](./pci_dss_v3.2.1/policy.sql) +- [AWS Foundational Security Best Practices](./foundational_security/policy.sql) +- [AWS Public Egress](./public_egress/policy.sql) +- [AWS Publicly Available](./publicly_available/policy.sql) + +## Running + +You can execute policies with `psql`. For example: + +```bash +# Execute the whole CIS Policy +psql -U postgres -f ./cis_v1.2.0/policy.sql +``` + +This will create all the results in `aws_policy_results` table which you can query directly, connect to any BI system (Grafana, Preset, AWS QuickSight, PowerBI, ...). + +You can also output it into CSV or HTML with the following built-in psql commands: + +``` +# default tabular output +psql -U postgres -c "select * from aws_policy_results" +# CSV output +psql -U postgres -c "select * from aws_policy_results" --csv +# HTML output +psql -U postgres -c "select * from aws_policy_results" --html +``` diff --git a/policies/cis_v1.2.0/policy.sql b/policies/cis_v1.2.0/policy.sql new file mode 100644 index 000000000..30cad00a4 --- /dev/null +++ b/policies/cis_v1.2.0/policy.sql @@ -0,0 +1,7 @@ +\set framework 'cis_v1.2.0' +\set execution_time ''''`date '+%Y-%m-%d %H:%M:%S'`''''::timestamp +\i create_aws_policy_results.sql +\i cis_v1.2.0/section_1.sql +\i cis_v1.2.0/section_2.sql +\i cis_v1.2.0/section_3.sql +\i cis_v1.2.0/section_4.sql diff --git a/policies/cis_v1.2.0/section_1.sql b/policies/cis_v1.2.0/section_1.sql new file mode 100644 index 000000000..78f809ef0 --- /dev/null +++ b/policies/cis_v1.2.0/section_1.sql @@ -0,0 +1,46 @@ +\echo "Executing CIS V1.2.0 Section 1" +\set check_id "1.1" +\echo "Executing check 1.1" +\i queries/iam/avoid_root_usage.sql +\set check_id "1.2" +\echo "Executing check 1.2" +\i queries/iam/mfa_enabled_for_console_access.sql +\set check_id "1.3" +\echo "Executing check 1.3" +\i queries/iam/unused_creds_disabled.sql +\set check_id "1.4" +\echo "Executing check 1.4" +\i queries/iam/old_access_keys.sql +\set check_id "1.5" +\echo "Executing check 1.5" +\i queries/iam/password_policy_min_uppercase.sql +\set check_id "1.6" +\echo "Executing check 1.6" +\i queries/iam/password_policy_min_lowercase.sql +\set check_id "1.7" +\echo "Executing check 1.7" +\i queries/iam/password_policy_min_one_symbol.sql +\set check_id "1.8" +\echo "Executing check 1.8" +\i queries/iam/password_policy_min_number.sql +\set check_id "1.9" +\echo "Executing check 1.9" +\i queries/iam/password_policy_min_length.sql +\set check_id "1.10" +\echo "Executing check 1.10" +\i queries/iam/password_policy_prevent_reuse.sql +\set check_id "1.11" +\echo "Executing check 1.11" +\i queries/iam/password_policy_expire_old_passwords.sql +\set check_id "1.12" +\echo "Executing check 1.12" +\i queries/iam/root_user_no_access_keys.sql +\set check_id "1.13" +\echo "Executing check 1.13" +\i queries/iam/mfa_enabled_for_root.sql +\set check_id "1.14" +\echo "Executing check 1.14" +\i queries/iam/hardware_mfa_enabled_for_root.sql +\set check_id "1.16" +\echo "Executing check 1.16" +\i queries/iam/policies_attached_to_groups_roles.sql diff --git a/policies/cis_v1.2.0/section_2.sql b/policies/cis_v1.2.0/section_2.sql new file mode 100644 index 000000000..f927bf9dc --- /dev/null +++ b/policies/cis_v1.2.0/section_2.sql @@ -0,0 +1,22 @@ +\echo "Executing CIS V1.2.0 Section 2" +\set check_id "2.1" +\echo "Executing check 2.1" +\i queries/cloudtrail/enabled_in_all_regions.sql +\set check_id "2.2" +\echo "Executing check 2.2" +\i queries/cloudtrail/log_file_validation_enabled.sql +\set check_id "2.4" +\echo "Executing check 2.4" +\i queries/cloudtrail/integrated_with_cloudwatch_logs.sql +\set check_id "2.6" +\echo "Executing check 2.6" +\i queries/cloudtrail/bucket_access_logging.sql +\set check_id "2.7" +\echo "Executing check 2.7" +\i queries/cloudtrail/logs_encrypted.sql +\set check_id "2.8" +\echo "Executing check 2.8" +\i queries/kms/rotation_enabled_for_customer_key.sql +\set check_id "2.9" +\echo "Executing check 2.9" +\i queries/ec2/flow_logs_enabled_in_all_vpcs.sql diff --git a/policies/cis_v1.2.0/section_3.sql b/policies/cis_v1.2.0/section_3.sql new file mode 100644 index 000000000..6707005b9 --- /dev/null +++ b/policies/cis_v1.2.0/section_3.sql @@ -0,0 +1,42 @@ +\echo "Executing CIS V1.2.0 Section 3" +\echo "Creating view_aws_log_metric_filter_and_alarm" +\i views/log_metric_filter_and_alarm.sql +\set check_id "3.1" +\echo "Executing check 3.1" +\i queries/cloudwatch/alarm_unauthorized_api.sql +\set check_id "3.3" +\echo "Executing check 3.3" +\i queries/cloudwatch/alarm_root_account.sql +\set check_id "3.4" +\echo "Executing check 3.4" +\i queries/cloudwatch/alarm_iam_policy_change.sql +\set check_id "3.5" +\echo "Executing check 3.5" +\i queries/cloudwatch/alarm_cloudtrail_config_changes.sql +\set check_id "3.6" +\echo "Executing check 3.6" +\i queries/cloudwatch/alarm_console_auth_failure.sql +\set check_id "3.7" +\echo "Executing check 3.7" +\i queries/cloudwatch/alarm_delete_customer_cmk.sql +\set check_id "3.8" +\echo "Executing check 3.8" +\i queries/cloudwatch/alarm_s3_bucket_policy_change.sql +\set check_id "3.9" +\echo "Executing check 3.9" +\i queries/cloudwatch/alarm_aws_config_changes.sql +\set check_id "3.10" +\echo "Executing check 3.10" +\i queries/cloudwatch/alarm_security_group_changes.sql +\set check_id "3.11" +\echo "Executing check 3.11" +\i queries/cloudwatch/alarm_nacl_changes.sql +\set check_id "3.12" +\echo "Executing check 3.12" +\i queries/cloudwatch/alarm_network_gateways.sql +\set check_id "3.13" +\echo "Executing check 3.13" +\i queries/cloudwatch/alarm_route_table_changes.sql +\set check_id "3.14" +\echo "Executing check 3.14" +\i queries/cloudwatch/alarm_vpc_changes.sql diff --git a/policies/cis_v1.2.0/section_4.sql b/policies/cis_v1.2.0/section_4.sql new file mode 100644 index 000000000..63491cb2a --- /dev/null +++ b/policies/cis_v1.2.0/section_4.sql @@ -0,0 +1,12 @@ +\echo "Executing CIS V1.2.0 Section 4" +\echo "Creating view_aws_security_group_ingress_rules" +\i views/security_group_ingress_rules.sql +\set check_id "4.1" +\echo "Executing check 4.1" +\i queries/ec2/no_broad_public_ingress_on_port_22.sql +\set check_id "4.2" +\echo "Executing check 4.2" +\i queries/ec2/no_broad_public_ingress_on_port_3389.sql +\set check_id "4.3" +\echo "Executing check 4.3" +\i queries/ec2/default_sg_no_access.sql diff --git a/policies/create_aws_policy_results.sql b/policies/create_aws_policy_results.sql new file mode 100644 index 000000000..7e84d9289 --- /dev/null +++ b/policies/create_aws_policy_results.sql @@ -0,0 +1,9 @@ +create table if not exists aws_policy_results ( + execution_time timestamp, + framework varchar(255), + check_id varchar(255), + title text, + account_id varchar(1024), + resource_id varchar(1024), + status varchar(16) +) \ No newline at end of file diff --git a/policies/foundational_security/acm.sql b/policies/foundational_security/acm.sql new file mode 100644 index 000000000..189318125 --- /dev/null +++ b/policies/foundational_security/acm.sql @@ -0,0 +1,3 @@ +\set check_id 'ACM.1' +\echo "Executing check ACM.1" +\i queries/acm/certificates_should_be_renewed.sql diff --git a/policies/foundational_security/apigateway.sql b/policies/foundational_security/apigateway.sql new file mode 100644 index 000000000..fd91c348c --- /dev/null +++ b/policies/foundational_security/apigateway.sql @@ -0,0 +1,22 @@ +\echo "Creating view_aws_apigateway_method_settings" +\i views/api_gateway_method_settings.sql + +\set check_id 'ApiGateway.1' +\echo "Executing check ApiGateway.1" +\i queries/apigateway/api_gw_execution_logging_enabled.sql + +\set check_id 'ApiGateway.2' +\echo "Executing check ApiGateway.2" +\i queries/apigateway/api_gw_ssl_enabled.sql + +\set check_id 'ApiGateway.3' +\echo "Executing check ApiGateway.3" +\i queries/apigateway/api_gw_xray_enabled.sql + +\set check_id 'ApiGateway.4' +\echo "Executing check ApiGateway.4" +\i queries/apigateway/api_gw_associated_with_waf.sql + +\set check_id 'ApiGateway.5' +\echo "Executing check ApiGateway.5" +\i queries/apigateway/api_gw_cache_encrypted.sql diff --git a/policies/foundational_security/autoscaling.sql b/policies/foundational_security/autoscaling.sql new file mode 100644 index 000000000..c3906ead9 --- /dev/null +++ b/policies/foundational_security/autoscaling.sql @@ -0,0 +1,3 @@ +\set check_id 'AutoScaling.1' +\echo "Executing check AutoScaling.1" +\i queries/autoscaling/autoscaling_groups_elb_check.sql diff --git a/policies/foundational_security/awsconfig.sql b/policies/foundational_security/awsconfig.sql new file mode 100644 index 000000000..f69d1e734 --- /dev/null +++ b/policies/foundational_security/awsconfig.sql @@ -0,0 +1,3 @@ +\set check_id 'Config.1' +\echo "Executing check Config.1" +\i queries/config/enabled_all_regions.sql diff --git a/policies/foundational_security/cloudfront.sql b/policies/foundational_security/cloudfront.sql new file mode 100644 index 000000000..e5500f206 --- /dev/null +++ b/policies/foundational_security/cloudfront.sql @@ -0,0 +1,23 @@ +\set check_id 'Cloudfront.1' +\echo "Executing check Cloudfront.1" +\i queries/cloudfront/default_root_object_configured.sql + +\set check_id 'Cloudfront.2' +\echo "Executing check Cloudfront.2" +\i queries/cloudfront/origin_access_identity_enabled.sql + +\set check_id 'Cloudfront.3' +\echo "Executing check Cloudfront.3" +\i queries/cloudfront/viewer_policy_https.sql + +\set check_id 'Cloudfront.4' +\echo "Executing check Cloudfront.4" +\i queries/cloudfront/origin_failover_enabled.sql + +\set check_id 'Cloudfront.5' +\echo "Executing check Cloudfront.5" +\i queries/cloudfront/access_logs_enabled.sql + +\set check_id 'Cloudfront.6' +\echo "Executing check Cloudfront.6" +\i queries/cloudfront/associated_with_waf.sql diff --git a/policies/foundational_security/cloudtrail.sql b/policies/foundational_security/cloudtrail.sql new file mode 100644 index 000000000..5cb4b8261 --- /dev/null +++ b/policies/foundational_security/cloudtrail.sql @@ -0,0 +1,15 @@ +\set check_id 'CloudTrail.1' +\echo "Executing check CloudTrail.1" +\i queries/cloudtrail/enabled_in_all_regions.sql + +\set check_id 'CloudTrail.2' +\echo "Executing check CloudTrail.2" +\i queries/cloudtrail/logs_encrypted.sql + +\set check_id 'CloudTrail.4' +\echo "Executing check CloudTrail.4" +\i queries/cloudtrail/log_file_validation_enabled.sql + +\set check_id 'CloudTrail.5' +\echo "Executing check CloudTrail.5" +\i queries/cloudtrail/integrated_with_cloudwatch_logs.sql diff --git a/policies/foundational_security/codebuild.sql b/policies/foundational_security/codebuild.sql new file mode 100644 index 000000000..51cd0fe9d --- /dev/null +++ b/policies/foundational_security/codebuild.sql @@ -0,0 +1,7 @@ +\set check_id 'CodeBuild.1' +\echo "Executing check CodeBuild.1" +\i queries/codebuild/check_oauth_usage_for_sources.sql + +\set check_id 'CodeBuild.2' +\echo "Executing check CodeBuild.2" +\i queries/codebuild/check_environment_variables.sql diff --git a/policies/foundational_security/dms.sql b/policies/foundational_security/dms.sql new file mode 100644 index 000000000..9d6eed9fb --- /dev/null +++ b/policies/foundational_security/dms.sql @@ -0,0 +1,3 @@ +\set check_id 'DMS.1' +\echo "Executing check DMS.1" +\i queries/dms/replication_not_public.sql diff --git a/policies/foundational_security/dynamodb.sql b/policies/foundational_security/dynamodb.sql new file mode 100644 index 000000000..f715301cc --- /dev/null +++ b/policies/foundational_security/dynamodb.sql @@ -0,0 +1,11 @@ +\set check_id 'DynamoDB.1' +\echo "Executing check DynamoDB.1" +\i queries/dynamodb/autoscale_or_ondemand.sql + +\set check_id 'DynamoDB.2' +\echo "Executing check DynamoDB.2" +\i queries/dynamodb/point_in_time_recovery.sql + +\set check_id 'DynamoDB.3' +\echo "Executing check DynamoDB.3" +\i queries/dynamodb/dax_encrypted_at_rest.sql diff --git a/policies/foundational_security/ec2.sql b/policies/foundational_security/ec2.sql new file mode 100644 index 000000000..d84304c58 --- /dev/null +++ b/policies/foundational_security/ec2.sql @@ -0,0 +1,59 @@ +\echo "Creating view_aws_security_group_ingress_rules" +\i views/security_group_ingress_rules.sql + +\set check_id 'EC2.1' +\echo "Executing check EC2.1" +\i queries/ec2/ebs_snapshot_permissions_check.sql + +\set check_id 'EC2.2' +\echo "Executing check EC2.2" +\i queries/ec2/default_sg_no_access.sql + +\set check_id 'EC2.3' +\echo "Executing check EC2.3" +\i queries/ec2/unencrypted_ebs_volumes.sql + +\set check_id 'EC2.4' +\echo "Executing check EC2.4" +\i queries/ec2/stopped_more_thant_30_days_ago_instances.sql + + +\set check_id 'EC2.6' +\echo "Executing check EC2.6" +\i queries/ec2/flow_logs_enabled_in_all_vpcs.sql + +\set check_id 'EC2.7' +\echo "Executing check EC2.7" +\i queries/ec2/ebs_encryption_by_default_disabled.sql + +\set check_id 'EC2.8' +\echo "Executing check EC2.8" +\i queries/ec2/not_imdsv2_instances.sql + +\set check_id 'EC2.9' +\echo "Executing check EC2.9" +\i queries/ec2/instances_with_public_ip.sql + +\set check_id 'EC2.10' +\echo "Executing check EC2.10" +\i queries/ec2/vpcs_without_ec2_endpoint.sql + +\set check_id 'EC2.15' +\echo "Executing check EC2.15" +\i queries/ec2/subnets_that_assign_public_ips.sql + +\set check_id 'EC2.16' +\echo "Executing check EC2.16" +\i queries/ec2/unused_acls.sql + +\set check_id 'EC2.17' +\echo "Executing check EC2.17" +\i queries/ec2/instances_with_more_than_2_network_interfaces.sql + +\set check_id 'EC2.18' +\echo "Executing check EC2.18" +\i queries/ec2/security_groups_with_access_to_unauthorized_ports.sql + +\set check_id 'EC2.19' +\echo "Executing check EC2.19" +\i queries/ec2/security_groups_with_open_critical_ports.sql diff --git a/policies/foundational_security/ecs.sql b/policies/foundational_security/ecs.sql new file mode 100644 index 000000000..6d392a87c --- /dev/null +++ b/policies/foundational_security/ecs.sql @@ -0,0 +1,7 @@ +\set check_id 'ECS.1' +\echo "Executing check ECS.1" +\i queries/ecs/task_definitions_secure_networking.sql + +\set check_id 'ECS.2' +\echo "Executing check ECS.2" +\i queries/ecs/ecs_services_with_public_ips.sql diff --git a/policies/foundational_security/efs.sql b/policies/foundational_security/efs.sql new file mode 100644 index 000000000..03e1da594 --- /dev/null +++ b/policies/foundational_security/efs.sql @@ -0,0 +1,7 @@ +\set check_id 'EFS.1' +\echo "Executing check EFS.1" +\i queries/efs/unencrypted_efs_filesystems.sql + +\set check_id 'EFS.2' +\echo "Executing check EFS.2" +\i queries/efs/efs_filesystems_with_disabled_backups.sql diff --git a/policies/foundational_security/elastic_beanstalk.sql b/policies/foundational_security/elastic_beanstalk.sql new file mode 100644 index 000000000..54d96dacb --- /dev/null +++ b/policies/foundational_security/elastic_beanstalk.sql @@ -0,0 +1,7 @@ +\set check_id 'ElasticBeanstalk.1' +\echo "Executing check ElasticBeanstalk.1" +\i queries/elasticbeanstalk/advanced_health_reporting_enabled.sql + +\set check_id 'ElasticBeanstalk.2' +\echo "Executing check ElasticBeanstalk.2" +\i queries/elasticbeanstalk/elastic_beanstalk_managed_updates_enabled.sql diff --git a/policies/foundational_security/elasticsearch.sql b/policies/foundational_security/elasticsearch.sql new file mode 100644 index 000000000..4d782d3bc --- /dev/null +++ b/policies/foundational_security/elasticsearch.sql @@ -0,0 +1,31 @@ +\set check_id 'Elasticsearch.1' +\echo "Executing check Elasticsearch.1" +\i queries/elasticsearch/elasticsearch_domains_should_have_encryption_at_rest_enabled.sql + +\set check_id 'Elasticsearch.2' +\echo "Executing check Elasticsearch.2" +\i queries/elasticsearch/elasticsearch_domains_should_be_in_vpc.sql + +\set check_id 'Elasticsearch.3' +\echo "Executing check Elasticsearch.3" +\i queries/elasticsearch/elasticsearch_domains_should_encrypt_data_sent_between_nodes.sql + +\set check_id 'Elasticsearch.4' +\echo "Executing check Elasticsearch.4" +\i queries/elasticsearch/elasticsearch_domain_error_logging_to_cloudwatch_logs_should_be_enabled.sql + +\set check_id 'Elasticsearch.5' +\echo "Executing check Elasticsearch.5" +\i queries/elasticsearch/elasticsearch_domains_should_have_audit_logging_enabled.sql + +\set check_id 'Elasticsearch.6' +\echo "Executing check Elasticsearch.6" +\i queries/elasticsearch/elasticsearch_domains_should_have_at_least_three_data_nodes.sql + +\set check_id 'Elasticsearch.7' +\echo "Executing check Elasticsearch.7" +\i queries/elasticsearch/elasticsearch_domains_should_be_configured_with_at_least_three_dedicated_master_nodes.sql + +\set check_id 'Elasticsearch.8' +\echo "Executing check Elasticsearch.8" +\i queries/elasticsearch/connections_to_elasticsearch_domains_should_be_encrypted_using_tls_1_2.sql diff --git a/policies/foundational_security/elb.sql b/policies/foundational_security/elb.sql new file mode 100644 index 000000000..a793a4b11 --- /dev/null +++ b/policies/foundational_security/elb.sql @@ -0,0 +1,27 @@ +\set check_id 'ELB.2' +\echo "Executing check ELB.2" +\i queries/elb/elbv1_cert_provided_by_acm.sql + +\set check_id 'ELB.3' +\echo "Executing check ELB.3" +\i queries/elb/elbv1_https_or_tls.sql + +\set check_id 'ELB.4' +\echo "Executing check ELB.4" +\i queries/elb/alb_drop_http_headers.sql + +\set check_id 'ELB.5' +\echo "Executing check ELB.5" +\i queries/elb/alb_logging_enabled.sql + +\set check_id 'ELB.6' +\echo "Executing check ELB.6" +\i queries/elb/alb_deletion_protection_enabled.sql + +\set check_id 'ELB.7' +\echo "Executing check ELB.7" +\i queries/elb/elbv1_conn_draining_enabled.sql + +\set check_id 'ELB.8' +\echo "Executing check ELB.8" +\i queries/elb/elbv1_https_predefined_policy.sql diff --git a/policies/foundational_security/elbv2.sql b/policies/foundational_security/elbv2.sql new file mode 100644 index 000000000..ba5b7d970 --- /dev/null +++ b/policies/foundational_security/elbv2.sql @@ -0,0 +1,3 @@ +\set check_id 'ELBv2.1' +\echo "Executing check ELBv2.1" +\i queries/elb/elbv2_redirect_http_to_https.sql diff --git a/policies/foundational_security/emr.sql b/policies/foundational_security/emr.sql new file mode 100644 index 000000000..ca9bb7a9c --- /dev/null +++ b/policies/foundational_security/emr.sql @@ -0,0 +1,3 @@ +\set check_id 'EMR.1' +\echo "Executing check EMR.1" +\i queries/emr/emr_cluster_master_nodes_should_not_have_public_ip_addresses.sql diff --git a/policies/foundational_security/guardduty.sql b/policies/foundational_security/guardduty.sql new file mode 100644 index 000000000..c2b885295 --- /dev/null +++ b/policies/foundational_security/guardduty.sql @@ -0,0 +1,3 @@ +\set check_id 'GuardDuty.1' +\echo "Executing check GuardDuty.1" +\i queries/guardduty/detector_enabled.sql diff --git a/policies/foundational_security/iam.sql b/policies/foundational_security/iam.sql new file mode 100644 index 000000000..087229598 --- /dev/null +++ b/policies/foundational_security/iam.sql @@ -0,0 +1,35 @@ +\set check_id 'IAM.1' +\echo "Executing check IAM.1" +\i queries/iam/policies_with_admin_rights.sql + +\set check_id 'IAM.2' +\echo "Executing check IAM.2" +\i queries/iam/policies_attached_to_groups_roles.sql + +\set check_id 'IAM.3' +\echo "Executing check IAM.3" +\i queries/iam/iam_access_keys_rotated_more_than_90_days.sql + +\set check_id 'IAM.4' +\echo "Executing check IAM.4" +\i queries/iam/root_user_no_access_keys.sql + +\set check_id 'IAM.5' +\echo "Executing check IAM.5" +\i queries/iam/mfa_enabled_for_console_access.sql + +\set check_id 'IAM.6' +\echo "Executing check IAM.6" +\i queries/iam/hardware_mfa_enabled_for_root.sql + +\set check_id 'IAM.7' +\echo "Executing check IAM.7" +\i queries/iam/password_policy_strong.sql + +\set check_id 'IAM.8' +\echo "Executing check IAM.8" +\i queries/iam/iam_access_keys_unused_more_than_90_days.sql + +\set check_id 'IAM.21' +\echo "Executing check IAM.21" +\i queries/iam/wildcard_access_policies.sql diff --git a/policies/foundational_security/kms.sql b/policies/foundational_security/kms.sql new file mode 100644 index 000000000..a7c61693e --- /dev/null +++ b/policies/foundational_security/kms.sql @@ -0,0 +1,11 @@ +\set check_id 'KMS.1' +\echo "Executing check KMS.1" +\i queries/kms/customer_policy_blocked_kms_actions.sql + +\set check_id 'KMS.2' +\echo "Executing check KMS.2" +\i queries/kms/inline_policy_blocked_kms_actions.sql + +\set check_id 'KMS.3' +\echo "Executing check KMS.3" +\i queries/kms/cmk_not_scheduled_for_deletion.sql diff --git a/policies/foundational_security/lambda.sql b/policies/foundational_security/lambda.sql new file mode 100644 index 000000000..97ec0add7 --- /dev/null +++ b/policies/foundational_security/lambda.sql @@ -0,0 +1,7 @@ +\set check_id 'Lambda.1' +\echo "Executing check Lambda.1" +\i queries/lambda/lambda_function_prohibit_public_access.sql + +\set check_id 'Lambda.2' +\echo "Executing check Lambda.2" +\i queries/lambda/lambda_functions_should_use_supported_runtimes.sql diff --git a/policies/foundational_security/policy.sql b/policies/foundational_security/policy.sql new file mode 100644 index 000000000..f9ef6b1e9 --- /dev/null +++ b/policies/foundational_security/policy.sql @@ -0,0 +1,33 @@ +\set framework 'foundational_security' +\set execution_time ''''`date '+%Y-%m-%d %H:%M:%S'`''''::timestamp +\i create_aws_policy_results.sql +\i foundational_security/acm.sql +\i foundational_security/apigateway.sql +\i foundational_security/autoscaling.sql +\i foundational_security/awsconfig.sql +\i foundational_security/cloudfront.sql +\i foundational_security/cloudtrail.sql +\i foundational_security/codebuild.sql +\i foundational_security/dms.sql +\i foundational_security/dynamodb.sql +\i foundational_security/ec2.sql +\i foundational_security/ecs.sql +\i foundational_security/efs.sql +\i foundational_security/elastic_beanstalk.sql +\i foundational_security/elasticsearch.sql +\i foundational_security/elb.sql +\i foundational_security/elbv2.sql +\i foundational_security/emr.sql +\i foundational_security/guardduty.sql +\i foundational_security/iam.sql +\i foundational_security/kms.sql +\i foundational_security/lambda.sql +\i foundational_security/rds.sql +\i foundational_security/redshift.sql +\i foundational_security/s3.sql +\i foundational_security/sagemaker.sql +\i foundational_security/secretmanager.sql +\i foundational_security/sns.sql +\i foundational_security/sqs.sql +\i foundational_security/ssm.sql +\i foundational_security/waf.sql diff --git a/policies/foundational_security/rds.sql b/policies/foundational_security/rds.sql new file mode 100644 index 000000000..4230a8c82 --- /dev/null +++ b/policies/foundational_security/rds.sql @@ -0,0 +1,87 @@ +\set check_id 'RDS.1' +\echo "Executing check RDS.1" +\i queries/rds/snapshots_should_prohibit_public_access.sql + +\set check_id 'RDS.2' +\echo "Executing check RDS.2" +\i queries/rds/rds_db_instances_should_prohibit_public_access.sql + +\set check_id 'RDS.3' +\echo "Executing check RDS.3" +\i queries/rds/rds_db_instances_should_have_encryption_at_rest_enabled.sql + +\set check_id 'RDS.4' +\echo "Executing check RDS.4" +\i queries/rds/rds_cluster_snapshots_and_database_snapshots_should_be_encrypted_at_rest.sql + +\set check_id 'RDS.5' +\echo "Executing check RDS.5" +\i queries/rds/rds_db_instances_should_be_configured_with_multiple_availability_zones.sql + +\set check_id 'RDS.6' +\echo "Executing check RDS.6" +\i queries/rds/enhanced_monitoring_should_be_configured_for_rds_db_instances_and_clusters.sql + +\set check_id 'RDS.7' +\echo "Executing check RDS.7" +\i queries/rds/rds_clusters_should_have_deletion_protection_enabled.sql + +\set check_id 'RDS.8' +\echo "Executing check RDS.8" +\i queries/rds/rds_db_instances_should_have_deletion_protection_enabled.sql + +\set check_id 'RDS.9' +\echo "Executing check RDS.9" +\i queries/rds/database_logging_should_be_enabled.sql + +\set check_id 'RDS.10' +\echo "Executing check RDS.10" +\i queries/rds/iam_authentication_should_be_configured_for_rds_instances.sql + +\set check_id 'RDS.12' +\echo "Executing check RDS.12" +\i queries/rds/iam_authentication_should_be_configured_for_rds_clusters.sql + +\set check_id 'RDS.13' +\echo "Executing check RDS.13" +\i queries/rds/rds_automatic_minor_version_upgrades_should_be_enabled.sql + +\set check_id 'RDS.14' +\echo "Executing check RDS.14" +\i queries/rds/amazon_aurora_clusters_should_have_backtracking_enabled.sql + +\set check_id 'RDS.15' +\echo "Executing check RDS.15" +\i queries/rds/rds_db_clusters_should_be_configured_for_multiple_availability_zones.sql + +\set check_id 'RDS.16' +\echo "Executing check RDS.16" +\i queries/rds/rds_db_clusters_should_be_configured_to_copy_tags_to_snapshots.sql + +\set check_id 'RDS.17' +\echo "Executing check RDS.17" +\i queries/rds/rds_db_instances_should_be_configured_to_copy_tags_to_snapshots.sql + +\set check_id 'RDS.18' +\echo "Executing check RDS.18" +\i queries/rds/rds_instances_should_be_deployed_in_a_vpc.sql + +\set check_id 'RDS.19' +\echo "Executing check RDS.19" +\i queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_cluster_events.sql + +\set check_id 'RDS.20' +\echo "Executing check RDS.20" +\i queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_database_instance_events.sql + +\set check_id 'RDS.21' +\echo "Executing check RDS.21" +\i queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_database_parameter_group_events.sql + +\set check_id 'RDS.22' +\echo "Executing check RDS.22" +\i queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_database_security_group_events.sql + +\set check_id 'RDS.23' +\echo "Executing check RDS.23" +\i queries/rds/rds_databases_and_clusters_should_not_use_a_database_engine_default_port.sql diff --git a/policies/foundational_security/redshift.sql b/policies/foundational_security/redshift.sql new file mode 100644 index 000000000..9049e809d --- /dev/null +++ b/policies/foundational_security/redshift.sql @@ -0,0 +1,23 @@ +\set check_id 'Redshift.1' +\echo "Executing check Redshift.1" +\i queries/redshift/cluster_publicly_accessible.sql + +\set check_id 'Redshift.2' +\echo "Executing check Redshift.2" +\i queries/redshift/clusters_should_be_encrypted_in_transit.sql + +\set check_id 'Redshift.3' +\echo "Executing check Redshift.3" +\i queries/redshift/clusters_should_have_automatic_snapshots_enabled.sql + +\set check_id 'Redshift.4' +\echo "Executing check Redshift.4" +\i queries/redshift/clusters_should_have_audit_logging_enabled.sql + +\set check_id 'Redshift.6' +\echo "Executing check Redshift.6" +\i queries/redshift/clusters_should_have_automatic_upgrades_to_major_versions_enabled.sql + +\set check_id 'Redshift.7' +\echo "Executing check Redshift.7" +\i queries/redshift/clusters_should_use_enhanced_vpc_routing.sql diff --git a/policies/foundational_security/s3.sql b/policies/foundational_security/s3.sql new file mode 100644 index 000000000..a04debdd7 --- /dev/null +++ b/policies/foundational_security/s3.sql @@ -0,0 +1,27 @@ +\set check_id 'S3.1' +\echo "Executing check S3.1" +\i queries/s3/account_level_public_access_blocks.sql + +\set check_id 'S3.2' +\echo "Executing check S3.2" +\i queries/s3/publicly_readable_buckets.sql + +\set check_id 'S3.3' +\echo "Executing check S3.3" +\i queries/s3/publicly_writable_buckets.sql + +\set check_id 'S3.4' +\echo "Executing check S3.4" +\i queries/s3/s3_server_side_encryption_enabled.sql + +\set check_id 'S3.5' +\echo "Executing check S3.5" +\i queries/s3/deny_http_requests.sql + +\set check_id 'S3.6' +\echo "Executing check S3.6" +\i queries/s3/restrict_cross_account_actions.sql + +\set check_id 'S3.8' +\echo "Executing check S3.8" +\i queries/s3/account_level_public_access_blocks.sql diff --git a/policies/foundational_security/sagemaker.sql b/policies/foundational_security/sagemaker.sql new file mode 100644 index 000000000..f66a8b21f --- /dev/null +++ b/policies/foundational_security/sagemaker.sql @@ -0,0 +1,3 @@ +\set check_id 'SageMaker.1' +\echo "Executing check SageMaker.1" +\i queries/sagemaker/sagemaker_notebook_instance_direct_internet_access_disabled.sql diff --git a/policies/foundational_security/secretmanager.sql b/policies/foundational_security/secretmanager.sql new file mode 100644 index 000000000..57b06d547 --- /dev/null +++ b/policies/foundational_security/secretmanager.sql @@ -0,0 +1,15 @@ +\set check_id 'SecretsManager.1' +\echo "Executing check SecretsManager.1" +\i queries/secretsmanager/secrets_should_have_automatic_rotation_enabled.sql + +\set check_id 'SecretsManager.2' +\echo "Executing check SecretsManager.2" +\i queries/secretsmanager/secrets_configured_with_automatic_rotation_should_rotate_successfully.sql + +\set check_id 'SecretsManager.3' +\echo "Executing check SecretsManager.3" +\i queries/secretsmanager/remove_unused_secrets_manager_secrets.sql + +\set check_id 'SecretsManager.4' +\echo "Executing check SecretsManager.4" +\i queries/secretsmanager/secrets_should_be_rotated_within_a_specified_number_of_days.sql diff --git a/policies/foundational_security/sns.sql b/policies/foundational_security/sns.sql new file mode 100644 index 000000000..ebe909451 --- /dev/null +++ b/policies/foundational_security/sns.sql @@ -0,0 +1,3 @@ +\set check_id 'SNS.1' +\echo "Executing check SNS.1" +\i queries/sns/sns_topics_should_be_encrypted_at_rest_using_aws_kms.sql diff --git a/policies/foundational_security/sqs.sql b/policies/foundational_security/sqs.sql new file mode 100644 index 000000000..0cb0019b9 --- /dev/null +++ b/policies/foundational_security/sqs.sql @@ -0,0 +1,3 @@ +\set check_id 'SQS.1' +\echo "Executing check SQS.1" +\i queries/sqs/sqs_queues_should_be_encrypted_at_rest_using_aws_kms.sql diff --git a/policies/foundational_security/ssm.sql b/policies/foundational_security/ssm.sql new file mode 100644 index 000000000..1d77b7243 --- /dev/null +++ b/policies/foundational_security/ssm.sql @@ -0,0 +1,15 @@ +\set check_id 'SSM.1' +\echo "Executing check SSM.1" +\i queries/ssm/ec2_instances_should_be_managed_by_ssm.sql + +\set check_id 'SSM.2' +\echo "Executing check SSM.2" +\i queries/ssm/instances_should_have_patch_compliance_status_of_compliant.sql + +\set check_id 'SSM.3' +\echo "Executing check SSM.3" +\i queries/ssm/instances_should_have_association_compliance_status_of_compliant.sql + +\set check_id 'SSM.4' +\echo "Executing check SSM.4" +\i queries/ssm/documents_should_not_be_public.sql diff --git a/policies/foundational_security/waf.sql b/policies/foundational_security/waf.sql new file mode 100644 index 000000000..b010dc14b --- /dev/null +++ b/policies/foundational_security/waf.sql @@ -0,0 +1,3 @@ +\set check_id 'WAF.1' +\echo "Executing check WAF.1" +\i queries/waf/waf_web_acl_logging_should_be_enabled.sql diff --git a/policies/pci_dss_v3.2.1/policy.sql b/policies/pci_dss_v3.2.1/policy.sql new file mode 100644 index 000000000..b39ff29ca --- /dev/null +++ b/policies/pci_dss_v3.2.1/policy.sql @@ -0,0 +1,206 @@ +\set framework 'pci_dss_v3.2.1' +\set execution_time ''''`date '+%Y-%m-%d %H:%M:%S'`''''::timestamp +\i create_aws_policy_results.sql + +\set check_id 'autoscaling.1' +\echo "Executing check autoscaling.1" +\i queries/autoscaling/autoscaling_groups_elb_check.sql + +\set check_id 'cloudtrail.1' +\echo "Executing check cloudtrail.1" +\i queries/cloudtrail/logs_encrypted.sql + +\set check_id 'cloudtrail.2' +\echo "Executing check cloudtrail.2" +\i queries/cloudtrail/enabled_in_all_regions.sql + +\set check_id 'cloudtrail.3' +\echo "Executing check cloudtrail.3" +\i queries/cloudtrail/log_file_validation_enabled.sql + +\set check_id 'cloudtrail.4' +\echo "Executing check cloudtrail.4" +\i queries/cloudtrail/integrated_with_cloudwatch_logs.sql + +\set check_id 'codebuild.1' +\echo "Executing check codebuild.1" +\i queries/codebuild/check_oauth_usage_for_sources.sql + +\set check_id 'codebuild.2' +\echo "Executing check codebuild.2" +\i queries/codebuild/check_environment_variables.sql + +\set check_id 'config.1' +\echo "Executing check config.1" +\i queries/config/enabled_all_regions.sql + +\echo "Creating view_aws_log_metric_filter_and_alarm" +\i views/log_metric_filter_and_alarm.sql + +\set check_id 'cloudwatch.1' +\echo "Executing check cloudwatch.1" +\i queries/cloudwatch/alarm_root_account.sql + +\set check_id 'dms.1' +\echo "Executing check dms.1" +\i queries/dms/replication_not_public.sql + +\echo "Creating view_aws_security_group_ingress_rules" +\i views/security_group_ingress_rules.sql + +\set check_id 'ec2.1' +\echo "Executing check ec2.1" +\i queries/ec2/ebs_snapshot_permissions_check.sql + +\set check_id 'ec2.2' +\echo "Executing check ec2.2" +\i queries/ec2/default_sg_no_access.sql + + +-- This control is retired. +-- Unused EC2 security groups should be removed (Retired) +-- \set check_id 'ec2.3' + +\set check_id 'ec2.4' +\echo "Executing check ec2.4" +\i queries/ec2/get_unused_public_ips.sql + +\set check_id 'ec2.5' +\echo "Executing check ec2.5" +\i queries/ec2/no_broad_public_ingress_on_port_22.sql + +\set check_id 'ec2.6' +\echo "Executing check ec2.6" +\i queries/ec2/flow_logs_enabled_in_all_vpcs.sql + +\set check_id 'elbv2.1' +\echo "Executing check elbv2.1" +\i queries/elb/elbv2_redirect_http_to_https.sql + +\set check_id 'elasticsearch.1' +\echo "Executing check elasticsearch.1" +\i queries/elasticsearch/elasticsearch_domains_should_be_in_vpc.sql + +\set check_id 'elasticsearch.2' +\echo "Executing check elasticsearch.2" +\i queries/elasticsearch/elasticsearch_domains_should_have_encryption_at_rest_enabled.sql + +\set check_id 'guardduty enabled in all enabled regions' +\echo "Executing check guardduty enabled in all enabled regions" +\i queries/guardduty/detector_enabled.sql + +\set check_id 'iam.1' +\echo "Executing check iam.1" +\i queries/iam/root_user_no_access_keys.sql + +\set check_id 'iam.2' +\echo "Executing check iam.2" +\i queries/iam/policies_attached_to_groups_roles.sql + +\set check_id 'iam.3' +\echo "Executing check iam.3" +\i queries/iam/no_star.sql + +\set check_id 'iam.4' +\echo "Executing check iam.4" +\i queries/iam/hardware_mfa_enabled_for_root.sql + +\set check_id 'iam.5' +\echo "Executing check iam.5" +\i queries/iam/mfa_enabled_for_root.sql + +\set check_id 'iam.6' +\echo "Executing check iam.6" +\i queries/iam/mfa_enabled_for_console_access.sql + +\set check_id 'iam.7' +\echo "Executing check iam.7" +\i queries/iam/unused_creds_disabled.sql + +\set check_id 'iam.8' +\echo "Executing check iam.8" +\i queries/iam/password_policy_strong.sql + +\set check_id 'kms.1' +\echo "Executing check kms.1" +\i queries/kms/rotation_enabled_for_customer_key.sql + +\set check_id 'lambda.1' +\echo "Executing check lambda.1" +\i queries/lambda/lambda_function_prohibit_public_access.sql + +\set check_id 'lambda.2' +\echo "Executing check lambda.2" +\i queries/lambda/lambda_function_in_vpc.sql + +\set check_id 'rds.1' +\echo "Executing check rds.1" +\i queries/rds/snapshots_should_prohibit_public_access.sql + +\set check_id 'rds.2' +\echo "Executing check rds.2" +\i queries/rds/rds_db_instances_should_prohibit_public_access.sql + +\set check_id 'redshift.1' +\echo "Executing check redshift.1" +\i queries/redshift/cluster_publicly_accessible.sql + +\set check_id 's3.1' +\echo "Executing check s3.1" +\i queries/s3/publicly_writable_buckets.sql + +\set check_id 's3.2' +\echo "Executing check s3.2" +\i queries/s3/publicly_readable_buckets.sql + +\set check_id 's3.3' +\echo "Executing check s3.3" +\i queries/s3/s3_cross_region_replication.sql + +\set check_id 's3.4' +\echo "Executing check s3.4" +\i queries/s3/s3_server_side_encryption_enabled.sql + +\set check_id 's3.5' +\echo "Executing check s3.5" +\i queries/s3/deny_http_requests.sql + +\set check_id 's3.6' +\echo "Executing check s3.6" +\i queries/s3/account_level_public_access_blocks.sql + +\set check_id 'sagemaker.1' +\echo "Executing check sagemaker.1" +\i queries/sagemaker/sagemaker_notebook_instance_direct_internet_access_disabled.sql + +\set check_id 'secretmanager.1' +\echo "Executing check secretmanager.1" +\i queries/secretsmanager/secrets_should_have_automatic_rotation_enabled.sql + +\set check_id 'secretmanager.2' +\echo "Executing check secretmanager.2" +\i queries/secretsmanager/secrets_configured_with_automatic_rotation_should_rotate_successfully.sql + +\set check_id 'secretmanager.3' +\echo "Executing check secretmanager.3" +\i queries/secretsmanager/remove_unused_secrets_manager_secrets.sql + +\set check_id 'secretmanager.4' +\echo "Executing check secretmanager.4" +\i queries/secretsmanager/secrets_should_be_rotated_within_a_specified_number_of_days.sql + +\set check_id 'ssm.1' +\echo "Executing check ssm.1" +\i queries/ssm/instances_should_have_patch_compliance_status_of_compliant.sql + +\set check_id 'ssm.2' +\echo "Executing check ssm.2" +\i queries/ssm/instances_should_have_association_compliance_status_of_compliant.sql + +\set check_id 'ssm.3' +\echo "Executing check ssm.3" +\i queries/ssm/ec2_instances_should_be_managed_by_ssm.sql + +\set check_id 'waf.1' +\echo "Executing check waf.1" +\i queries/wafv2/wafv2_web_acl_logging_should_be_enabled.sql diff --git a/policies/policy.sql b/policies/policy.sql new file mode 100644 index 000000000..8df69ae52 --- /dev/null +++ b/policies/policy.sql @@ -0,0 +1,6 @@ +\set ON_ERROR_STOP on +\i cis_v1.2.0/policy.sql +\i pci_dss_v3.2.1/policy.sql +\i foundational_security/policy.sql +\i public_egress/policy.sql +\i publicly_available/policy.sql diff --git a/policies/public_egress/policy.sql b/policies/public_egress/policy.sql new file mode 100644 index 000000000..049dbdb61 --- /dev/null +++ b/policies/public_egress/policy.sql @@ -0,0 +1,18 @@ +\set framework 'public_egress' +\set execution_time ''''`date '+%Y-%m-%d %H:%M:%S'`''''::timestamp +\i create_aws_policy_results.sql + +\echo "Creating view_aws_security_group_egress_rules" +\i views/security_group_egress_rules.sql + +\set check_id 'ec2-all-instances-with-routes-and-security-groups' +\echo "Executing check ec2-all-instances-with-routes-and-security-groups" +\i queries/ec2/public_egress_sg_and_routing_instances.sql + +\set check_id 'ec2-instances' +\echo "Executing check ec2-instances" +\i queries/ec2/public_egress_sg_instances.sql + +\set check_id 'lambda-functions' +\echo "Executing check lambda-functions" +\i queries/lambda/functions_with_public_egress.sql diff --git a/policies/publicly_available/policy.sql b/policies/publicly_available/policy.sql new file mode 100644 index 000000000..67b52d114 --- /dev/null +++ b/policies/publicly_available/policy.sql @@ -0,0 +1,35 @@ +\set framework 'publicly_available' +\set execution_time ''''`date '+%Y-%m-%d %H:%M:%S'`''''::timestamp +\i create_aws_policy_results.sql + +\set check_id 'API-Gateways' +\echo "Executing check API-Gateways" +\i queries/apigateway/api_gw_publicly_accessible.sql + +\set check_id 'API-Gateway-V2' +\echo "Executing check API-Gateway-V2" +\i queries/apigateway/api_gw_v2_publicly_accessible.sql + +\set check_id 'CloudFront-Distributions' +\echo "Executing check CloudFront-Distributions" +\i queries/cloudfront/all_distributions.sql + +\set check_id 'EC2-Public-Ips' +\echo "Executing check EC2-Public-Ips" +\i queries/ec2/public_ips.sql + +\set check_id 'ELB-Classic' +\echo "Executing check ELB-Classic" +\i queries/elb/elbv1_internet_facing.sql + +\set check_id 'ELB-V2' +\echo "Executing check ELB-V2" +\i queries/elb/elbv2_internet_facing.sql + +\set check_id 'Redshift' +\echo "Executing check Redshift" +\i queries/redshift/cluster_publicly_accessible.sql + +\set check_id 'RDS' +\echo "Executing check RDS" +\i queries/rds/rds_db_instances_should_prohibit_public_access.sql diff --git a/policies/queries/acm/certificates_should_be_renewed.sql b/policies/queries/acm/certificates_should_be_renewed.sql new file mode 100644 index 000000000..2a8f5b5e2 --- /dev/null +++ b/policies/queries/acm/certificates_should_be_renewed.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'certificate has less than 30 days to be renewed' as title, + account_id, + arn AS resource_id, + case when + not_after < NOW() AT TIME ZONE 'UTC' + INTERVAL '30' DAY + then 'fail' + else 'pass' + end as status +FROM aws_acm_certificates diff --git a/policies/queries/apigateway/api_gw_associated_with_waf.sql b/policies/queries/apigateway/api_gw_associated_with_waf.sql new file mode 100644 index 000000000..73501bdc0 --- /dev/null +++ b/policies/queries/apigateway/api_gw_associated_with_waf.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'API Gateway should be associated with an AWS WAF web ACL' AS title, + account_id, + arn as resource_id, + case + when waf is null then 'fail' + else 'pass' + end as status +from + view_aws_apigateway_method_settings diff --git a/policies/queries/apigateway/api_gw_cache_encrypted.sql b/policies/queries/apigateway/api_gw_cache_encrypted.sql new file mode 100644 index 000000000..2d510a0d6 --- /dev/null +++ b/policies/queries/apigateway/api_gw_cache_encrypted.sql @@ -0,0 +1,18 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'API Gateway REST API cache data should be encrypted at rest' AS title, + account_id, + arn as resource_id, + case + when stage_caching_enabled is true + or ( + caching_enabled is true + and cache_data_encrypted is not true + ) then 'pass' + else 'fail' + end as status +from + view_aws_apigateway_method_settings diff --git a/policies/queries/apigateway/api_gw_execution_logging_enabled.sql b/policies/queries/apigateway/api_gw_execution_logging_enabled.sql new file mode 100644 index 000000000..3a072bd63 --- /dev/null +++ b/policies/queries/apigateway/api_gw_execution_logging_enabled.sql @@ -0,0 +1,36 @@ +insert into aws_policy_results +(select distinct + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'API Gateway REST and WebSocket API logging should be enabled' as title, + r.account_id, + 'arn:' || 'aws' || ':apigateway:' || r.region || ':/restapis/' || r.id as resource_id, + case + when s.logging_level not in ('ERROR', 'INFO') then 'fail' + else 'pass' + end as status +from + view_aws_apigateway_method_settings s +left join + aws_apigateway_rest_apis r on s.rest_api_cq_id = r.cq_id +) + +union + +(select distinct + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'API Gateway REST and WebSocket API logging should be enabled' as title, + a.account_id, + 'arn:' || 'aws' || ':apigateway:' || a.region || ':/apis/' || a.id as resource_id, + case + when s.route_settings_logging_level in (NULL, 'OFF') then 'fail' + else 'pass' + end as status +from + aws_apigatewayv2_api_stages s +left join + aws_apigatewayv2_apis a on s.api_cq_id = a.cq_id +) diff --git a/policies/queries/apigateway/api_gw_publicly_accessible.sql b/policies/queries/apigateway/api_gw_publicly_accessible.sql new file mode 100644 index 000000000..7a9507696 --- /dev/null +++ b/policies/queries/apigateway/api_gw_publicly_accessible.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Find all API Gateway instances that are publicly accessible' AS title, + account_id, + arn as resource_id, + case + when NOT '{PRIVATE}' = endpoint_configuration_types then 'fail' + else 'pass' + end as status +from + aws_apigateway_rest_apis diff --git a/policies/queries/apigateway/api_gw_ssl_enabled.sql b/policies/queries/apigateway/api_gw_ssl_enabled.sql new file mode 100644 index 000000000..deec3eaaf --- /dev/null +++ b/policies/queries/apigateway/api_gw_ssl_enabled.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'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 cert is null then 'fail' + else 'pass' + end as status +from + view_aws_apigateway_method_settings diff --git a/policies/queries/apigateway/api_gw_v2_publicly_accessible.sql b/policies/queries/apigateway/api_gw_v2_publicly_accessible.sql new file mode 100644 index 000000000..d172d3831 --- /dev/null +++ b/policies/queries/apigateway/api_gw_v2_publicly_accessible.sql @@ -0,0 +1,11 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Find all API Gateway V2 instances (HTTP and Webhook) that are publicly accessible' AS title, + account_id, + arn as resource_id, + 'fail' as status +from + aws_apigatewayv2_apis diff --git a/policies/queries/apigateway/api_gw_xray_enabled.sql b/policies/queries/apigateway/api_gw_xray_enabled.sql new file mode 100644 index 000000000..ad7c6c83d --- /dev/null +++ b/policies/queries/apigateway/api_gw_xray_enabled.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'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 (stage_data_trace_enabled is not true or caching_enabled is not true) then 'fail' + else 'pass' + end as status +from + view_aws_apigateway_method_settings diff --git a/policies/queries/autoscaling/autoscaling_groups_elb_check.sql b/policies/queries/autoscaling/autoscaling_groups_elb_check.sql new file mode 100644 index 000000000..7b6e68967 --- /dev/null +++ b/policies/queries/autoscaling/autoscaling_groups_elb_check.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Auto Scaling groups associated with a load balancer should use health checks' as title, + account_id, + arn as resource_id, + case + when ARRAY_LENGTH(load_balancer_names, 1) > 0 and health_check_type is distinct from 'ELB' then 'fail' + else 'pass' + end as status +from aws_autoscaling_groups + diff --git a/policies/queries/cloudfront/access_logs_enabled.sql b/policies/queries/cloudfront/access_logs_enabled.sql new file mode 100644 index 000000000..c77d565ca --- /dev/null +++ b/policies/queries/cloudfront/access_logs_enabled.sql @@ -0,0 +1,13 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'CloudFront distributions should have logging enabled' as title, + account_id, + arn as resource_id, + case + when logging_enabled = true then 'fail' + else 'pass' + end as status +from aws_cloudfront_distributions diff --git a/policies/queries/cloudfront/all_distributions.sql b/policies/queries/cloudfront/all_distributions.sql new file mode 100644 index 000000000..545bf7900 --- /dev/null +++ b/policies/queries/cloudfront/all_distributions.sql @@ -0,0 +1,11 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Find all Cloudfront distributions' AS title, + account_id, + arn as resource_id, + 'fail' as status +from + aws_cloudfront_distributions diff --git a/policies/queries/cloudfront/associated_with_waf.sql b/policies/queries/cloudfront/associated_with_waf.sql new file mode 100644 index 000000000..adf6220de --- /dev/null +++ b/policies/queries/cloudfront/associated_with_waf.sql @@ -0,0 +1,13 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'API Gateway should be associated with an AWS WAF web ACL' as title, + account_id, + arn as resource_id, + case + when web_acl_id = '' then 'fail' + else 'pass' + end as status +from aws_cloudfront_distributions diff --git a/policies/queries/cloudfront/default_root_object_configured.sql b/policies/queries/cloudfront/default_root_object_configured.sql new file mode 100644 index 000000000..956f5412a --- /dev/null +++ b/policies/queries/cloudfront/default_root_object_configured.sql @@ -0,0 +1,13 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'CloudFront distributions should have a default root object configured' as title, + account_id, + arn as resource_id, + case + when default_root_object = '' then 'fail' + else 'pass' + end as status +from aws_cloudfront_distributions diff --git a/policies/queries/cloudfront/origin_access_identity_enabled.sql b/policies/queries/cloudfront/origin_access_identity_enabled.sql new file mode 100644 index 000000000..c547e585d --- /dev/null +++ b/policies/queries/cloudfront/origin_access_identity_enabled.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'CloudFront distributions should have origin access identity enabled' as title, + d.account_id, + d.arn as resource_id, + case + when o.domain_name like '%s3.amazonaws.com' and o.s3_origin_config_origin_access_identity = '' then 'fail' + else 'pass' + end as status +from aws_cloudfront_distribution_origins o +inner join aws_cloudfront_distributions d on d.cq_id = o.distribution_cq_id diff --git a/policies/queries/cloudfront/origin_failover_enabled.sql b/policies/queries/cloudfront/origin_failover_enabled.sql new file mode 100644 index 000000000..c3ce69004 --- /dev/null +++ b/policies/queries/cloudfront/origin_failover_enabled.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'CloudFront distributions should have origin failover configured' as title, + d.account_id, + d.arn as resource_id, + case + when members_origin_ids is null then 'fail' + else 'pass' + end as status +from aws_cloudfront_distribution_origin_groups o +inner join aws_cloudfront_distributions d on d.cq_id = o.distribution_cq_id diff --git a/policies/queries/cloudfront/viewer_policy_https.sql b/policies/queries/cloudfront/viewer_policy_https.sql new file mode 100644 index 000000000..1af3d4c94 --- /dev/null +++ b/policies/queries/cloudfront/viewer_policy_https.sql @@ -0,0 +1,20 @@ +insert into aws_policy_results +with data as ( + select distinct distribution_cq_id + from aws_cloudfront_distribution_cache_behaviors + where viewer_protocol_policy = 'allow-all' +) +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'CloudFront distributions should require encryption in transit' as title, + d.account_id, + d.arn as resource_id, + case + when data.distribution_cq_id is not null + or d.cache_behavior_viewer_protocol_policy = 'allow-all' then 'fail' + else 'pass' + end as status +from aws_cloudfront_distributions d +left join data on data.distribution_cq_id = d.cq_id diff --git a/policies/queries/cloudtrail-trail-logs-encrypted-with-kms-keys.sql b/policies/queries/cloudtrail-trail-logs-encrypted-with-kms-keys.sql new file mode 100644 index 000000000..f8ddb534d --- /dev/null +++ b/policies/queries/cloudtrail-trail-logs-encrypted-with-kms-keys.sql @@ -0,0 +1,12 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + '' as title, + account_id, + arn as resource_id, + case when + kms_key_id is null + then 'fail' else 'pass' end as status +from aws_cloudtrail_trails diff --git a/policies/queries/cloudtrail/bucket_access_logging.sql b/policies/queries/cloudtrail/bucket_access_logging.sql new file mode 100644 index 000000000..a8dfa6056 --- /dev/null +++ b/policies/queries/cloudtrail/bucket_access_logging.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket' as title, + t.account_id, + t.arn as resource_id, + case + when b.logging_target_bucket is null or b.logging_target_prefix is null then 'fail' + else 'pass' + end as status +from aws_cloudtrail_trails t +inner join aws_s3_buckets b on t.s3_bucket_name = b.name diff --git a/policies/queries/cloudtrail/enabled_in_all_regions.sql b/policies/queries/cloudtrail/enabled_in_all_regions.sql new file mode 100644 index 000000000..00ba6cb0e --- /dev/null +++ b/policies/queries/cloudtrail/enabled_in_all_regions.sql @@ -0,0 +1,19 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure CloudTrail is enabled in all regions' as title, + account_id, + arn as resource_id, + case + when is_multi_region_trail = FALSE or ( + is_multi_region_trail = TRUE and ( + read_write_type != 'All' or include_management_events = FALSE + )) then 'fail' + else 'pass' + end as status +from aws_cloudtrail_trails +inner join + aws_cloudtrail_trail_event_selectors on + aws_cloudtrail_trails.cq_id = aws_cloudtrail_trail_event_selectors.trail_cq_id diff --git a/policies/queries/cloudtrail/integrated_with_cloudwatch_logs.sql b/policies/queries/cloudtrail/integrated_with_cloudwatch_logs.sql new file mode 100644 index 000000000..f56365eff --- /dev/null +++ b/policies/queries/cloudtrail/integrated_with_cloudwatch_logs.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'CloudTrail trails should be integrated with CloudWatch Logs' as title, + account_id, + arn as resource_id, + case + when cloud_watch_logs_log_group_arn is null + OR latest_cloud_watch_logs_delivery_time < (now() - '1 days'::INTERVAL) + then 'fail' + else 'pass' + end as status +from aws_cloudtrail_trails diff --git a/policies/queries/cloudtrail/log_file_validation_enabled.sql b/policies/queries/cloudtrail/log_file_validation_enabled.sql new file mode 100644 index 000000000..0f87d26fa --- /dev/null +++ b/policies/queries/cloudtrail/log_file_validation_enabled.sql @@ -0,0 +1,13 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'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 diff --git a/policies/queries/cloudtrail/logs_encrypted.sql b/policies/queries/cloudtrail/logs_encrypted.sql new file mode 100644 index 000000000..ea2a25318 --- /dev/null +++ b/policies/queries/cloudtrail/logs_encrypted.sql @@ -0,0 +1,13 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'CloudTrail should have encryption at rest enabled' as title, + account_id, + arn as resource_id, + case + when kms_key_id is NULL then 'fail' + else 'pass' + end as status +FROM aws_cloudtrail_trails diff --git a/policies/queries/cloudwatch/alarm_aws_config_changes.sql b/policies/queries/cloudwatch/alarm_aws_config_changes.sql new file mode 100644 index 000000000..ecf8a8495 --- /dev/null +++ b/policies/queries/cloudwatch/alarm_aws_config_changes.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)' as title, + account_id, + cloud_watch_logs_log_group_arn as resource_id, + case + when pattern = '{($.eventSource = kms.amazonaws.com) ' + || '&& (($.eventName=DisableKey)||($.eventName=ScheduleKeyDeletion)) }"' then 'pass' + else 'fail' + end as status +from view_aws_log_metric_filter_and_alarm diff --git a/policies/queries/cloudwatch/alarm_cloudtrail_config_changes.sql b/policies/queries/cloudwatch/alarm_cloudtrail_config_changes.sql new file mode 100644 index 000000000..10b859d2c --- /dev/null +++ b/policies/queries/cloudwatch/alarm_cloudtrail_config_changes.sql @@ -0,0 +1,17 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)' as title, + account_id, + cloud_watch_logs_log_group_arn as resource_id, + case + when pattern = '{ ($.eventName = CreateTrail) ' + || '|| ($.eventName = UpdateTrail) ' + || '|| ($.eventName = DeleteTrail) ' + || '|| ($.eventName = StartLogging) ' + || '|| ($.eventName = StopLogging) }' then 'pass' + else 'fail' + end as status +from view_aws_log_metric_filter_and_alarm diff --git a/policies/queries/cloudwatch/alarm_console_auth_failure.sql b/policies/queries/cloudwatch/alarm_console_auth_failure.sql new file mode 100644 index 000000000..5ea32602b --- /dev/null +++ b/policies/queries/cloudwatch/alarm_console_auth_failure.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored)' as title, + account_id, + cloud_watch_logs_log_group_arn as resource_id, + case + when pattern = '{ ($.eventName = ConsoleLogin) ' + || '&& ($.errorMessage = "Failed authentication") }' then 'pass' + else 'fail' + end as status +from view_aws_log_metric_filter_and_alarm diff --git a/policies/queries/cloudwatch/alarm_console_no_mfa.sql b/policies/queries/cloudwatch/alarm_console_no_mfa.sql new file mode 100644 index 000000000..71ed02d50 --- /dev/null +++ b/policies/queries/cloudwatch/alarm_console_no_mfa.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + '' as title, + account_id, + cloud_watch_logs_log_group_arn as resource_id, + case + when pattern = '{ ($.errorCode = "ConsoleLogin") ' + || '|| ($.additionalEventData.MFAUsed != "Yes") }' then 'pass' + else 'fail' + end as status +from view_aws_log_metric_filter_and_alarm diff --git a/policies/queries/cloudwatch/alarm_delete_customer_cmk.sql b/policies/queries/cloudwatch/alarm_delete_customer_cmk.sql new file mode 100644 index 000000000..804a6046b --- /dev/null +++ b/policies/queries/cloudwatch/alarm_delete_customer_cmk.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored)' as title, + account_id, + cloud_watch_logs_log_group_arn as resource_id, + case + when pattern = '{($.eventSource = kms.amazonaws.com) ' + || '&& (($.eventName=DisableKey) ' + || '|| ($.eventName=ScheduleKeyDeletion)) }"' then 'pass' + else 'fail' + end as status +from view_aws_log_metric_filter_and_alarm diff --git a/policies/queries/cloudwatch/alarm_iam_policy_change.sql b/policies/queries/cloudwatch/alarm_iam_policy_change.sql new file mode 100644 index 000000000..224ea9926 --- /dev/null +++ b/policies/queries/cloudwatch/alarm_iam_policy_change.sql @@ -0,0 +1,28 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure a log metric filter and alarm exist for IAM policy changes (Score)' as title, + account_id, + cloud_watch_logs_log_group_arn as resource_id, + case + when pattern = '{ ($.eventName = DeleteGroupPolicy) ' + || '|| ($.eventName = DeleteRolePolicy) ' + || '|| ($.eventName = DeleteUserPolicy) ' + || '|| ($.eventName = PutGroupPolicy) ' + || '|| ($.eventName = PutRolePolicy) ' + || '|| ($.eventName = PutUserPolicy) ' + || '|| ($.eventName = CreatePolicy) ' + || '|| ($.eventName = DeletePolicy) ' + || '|| ($.eventName=CreatePolicyVersion) ' + || '|| ($.eventName=DeletePolicyVersion) ' + || '|| ($.eventName=AttachRolePolicy) ' + || '|| ($.eventName=DetachRolePolicy) ' + || '|| ($.eventName=AttachUserPolicy) ' + || '|| ($.eventName = DetachUserPolicy) ' + || '|| ($.eventName = AttachGroupPolicy) ' + || '|| ($.eventName = DetachGroupPolicy)}' then 'pass' + else 'fail' + end as status +from view_aws_log_metric_filter_and_alarm diff --git a/policies/queries/cloudwatch/alarm_nacl_changes.sql b/policies/queries/cloudwatch/alarm_nacl_changes.sql new file mode 100644 index 000000000..caf90021b --- /dev/null +++ b/policies/queries/cloudwatch/alarm_nacl_changes.sql @@ -0,0 +1,18 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored)' as title, + account_id, + cloud_watch_logs_log_group_arn as resource_id, + case + when pattern = '{ ($.eventName = CreateNetworkAcl) ' + || '|| ($.eventName = CreateNetworkAclEntry) ' + || '|| ($.eventName = DeleteNetworkAcl) ' + || '|| ($.eventName = DeleteNetworkAclEntry) ' + || '|| ($.eventName = ReplaceNetworkAclEntry) ' + || '|| ($.eventName = ReplaceNetworkAclAssociation) }' then 'pass' + else 'fail' + end as status +from view_aws_log_metric_filter_and_alarm diff --git a/policies/queries/cloudwatch/alarm_network_gateways.sql b/policies/queries/cloudwatch/alarm_network_gateways.sql new file mode 100644 index 000000000..82b60d028 --- /dev/null +++ b/policies/queries/cloudwatch/alarm_network_gateways.sql @@ -0,0 +1,18 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure a log metric filter and alarm exist for changes to network gateways (Scored)' as title, + account_id, + cloud_watch_logs_log_group_arn as resource_id, + case + when pattern = '{ ($.eventName = CreateCustomerGateway) ' + || '|| ($.eventName = DeleteCustomerGateway) ' + || '|| ($.eventName = AttachInternetGateway) ' + || '|| ($.eventName = CreateInternetGateway) ' + || '|| ($.eventName = DeleteInternetGateway) ' + || '|| ($.eventName = DetachInternetGateway) }' then 'pass' + else 'fail' + end as status +from view_aws_log_metric_filter_and_alarm diff --git a/policies/queries/cloudwatch/alarm_root_account.sql b/policies/queries/cloudwatch/alarm_root_account.sql new file mode 100644 index 000000000..879c2be1e --- /dev/null +++ b/policies/queries/cloudwatch/alarm_root_account.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure a log metric filter and alarm exist for usage of "root" account (Score)' as title, + account_id, + cloud_watch_logs_log_group_arn as resource_id, + case + when pattern = '{ $.userIdentity.type = "Root" ' + || '&& $.userIdentity.invokedBy NOT EXISTS ' + || '&& $.eventType != "AwsServiceEvent" }' then 'pass' + else 'fail' + end as title +from view_aws_log_metric_filter_and_alarm diff --git a/policies/queries/cloudwatch/alarm_route_table_changes.sql b/policies/queries/cloudwatch/alarm_route_table_changes.sql new file mode 100644 index 000000000..ea3977082 --- /dev/null +++ b/policies/queries/cloudwatch/alarm_route_table_changes.sql @@ -0,0 +1,19 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure a log metric filter and alarm exist for route table changes (Scored)' as title, + account_id, + cloud_watch_logs_log_group_arn, + case when + pattern = '{ ($.eventName = CreateRoute) ' + || '|| ($.eventName = CreateRouteTable) ' + || '|| ($.eventName = ReplaceRoute) ' + || '|| ($.eventName = ReplaceRouteTableAssociation) ' + || '|| ($.eventName = DeleteRouteTable) ' + || '|| ($.eventName = DeleteRoute) ' + || '|| ($.eventName = DisassociateRouteTable) }' then 'pass' + else 'fail' + end as status +from view_aws_log_metric_filter_and_alarm diff --git a/policies/queries/cloudwatch/alarm_s3_bucket_policy_change.sql b/policies/queries/cloudwatch/alarm_s3_bucket_policy_change.sql new file mode 100644 index 000000000..914ffabf9 --- /dev/null +++ b/policies/queries/cloudwatch/alarm_s3_bucket_policy_change.sql @@ -0,0 +1,22 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)' as title, + account_id, + cloud_watch_logs_log_group_arn as resource_id, + case + when pattern = '{ ($.eventSource = s3.amazonaws.com) ' + || '&& (($.eventName = PutBucketAcl) ' + || '|| ($.eventName = PutBucketPolicy) ' + || '|| ($.eventName = PutBucketCors) ' + || '|| ($.eventName = PutBucketLifecycle) ' + || '|| ($.eventName = PutBucketReplication) ' + || '|| ($.eventName = DeleteBucketPolicy) ' + || '|| ($.eventName = DeleteBucketCors) ' + || '|| ($.eventName = DeleteBucketLifecycle) ' + || '|| ($.eventName = DeleteBucketReplication)) }' + then 'fail' + end as status +from view_aws_log_metric_filter_and_alarm diff --git a/policies/queries/cloudwatch/alarm_security_group_changes.sql b/policies/queries/cloudwatch/alarm_security_group_changes.sql new file mode 100644 index 000000000..779dd5e84 --- /dev/null +++ b/policies/queries/cloudwatch/alarm_security_group_changes.sql @@ -0,0 +1,18 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure a log metric filter and alarm exist for security group changes (Scored)' as title, + account_id, + cloud_watch_logs_log_group_arn as resource_id, + case when + pattern = '{ ($.eventName = AuthorizeSecurityGroupIngress) ' + || '|| ($.eventName = AuthorizeSecurityGroupEgress) ' + || '|| ($.eventName = RevokeSecurityGroupIngress) ' + || '|| ($.eventName = RevokeSecurityGroupEgress) ' + || '|| ($.eventName = CreateSecurityGroup) ' + || '|| ($.eventName = DeleteSecurityGroup) }' then 'pass' + else 'fail' + end as status +from view_aws_log_metric_filter_and_alarm diff --git a/policies/queries/cloudwatch/alarm_unauthorized_api.sql b/policies/queries/cloudwatch/alarm_unauthorized_api.sql new file mode 100644 index 000000000..0ad5858d6 --- /dev/null +++ b/policies/queries/cloudwatch/alarm_unauthorized_api.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored)' as title, + account_id, + cloud_watch_logs_log_group_arn as resource_id, + case when + pattern = '{ ($.errorCode = "*UnauthorizedOperation") ' + || '|| ($.errorCode = "AccessDenied*") }' then 'pass' + else 'fail' + end as status +from view_aws_log_metric_filter_and_alarm diff --git a/policies/queries/cloudwatch/alarm_vpc_changes.sql b/policies/queries/cloudwatch/alarm_vpc_changes.sql new file mode 100644 index 000000000..61ccdf0c8 --- /dev/null +++ b/policies/queries/cloudwatch/alarm_vpc_changes.sql @@ -0,0 +1,24 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure a log metric filter and alarm exist for VPC changes (Scored)' as title, + account_id, + cloud_watch_logs_log_group_arn as resource_id, + case when + pattern = '{ ($.eventName = CreateVpc) ' + || '|| ($.eventName = DeleteVpc) ' + || '|| ($.eventName = ModifyVpcAttribute) ' + || '|| ($.eventName = AcceptVpcPeeringConnection) ' + || '|| ($.eventName = CreateVpcPeeringConnection) ' + || '|| ($.eventName = DeleteVpcPeeringConnection) ' + || '|| ($.eventName = RejectVpcPeeringConnection) ' + || '|| ($.eventName = AttachClassicLinkVpc) ' + || '|| ($.eventName = DetachClassicLinkVpc) ' + || '|| ($.eventName = DisableVpcClassicLink) ' + || '|| ($.eventName = EnableVpcClassicLink) }' + then 'pass' + else 'fail' + end as status +from view_aws_log_metric_filter_and_alarm diff --git a/policies/queries/codebuild/check_environment_variables.sql b/policies/queries/codebuild/check_environment_variables.sql new file mode 100644 index 000000000..2ec685413 --- /dev/null +++ b/policies/queries/codebuild/check_environment_variables.sql @@ -0,0 +1,25 @@ +insert into aws_policy_results +select distinct + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'CodeBuild project environment variables should not contain clear text credentials' as title, + account_id, + arn as resource_id, + case when + aws_codebuild_project_environment_variables.type = 'PLAINTEXT' + and ( + UPPER( + aws_codebuild_project_environment_variables.name + ) like '%ACCESS_KEY%' or UPPER( + aws_codebuild_project_environment_variables.name + ) like '%SECRET%' or UPPER( + aws_codebuild_project_environment_variables.name + ) like '%PASSWORD%' + ) + then 'fail' + else 'pass' + end as status +from aws_codebuild_projects + inner join aws_codebuild_project_environment_variables on + aws_codebuild_projects.cq_id = aws_codebuild_project_environment_variables.project_cq_id diff --git a/policies/queries/codebuild/check_oauth_usage_for_sources.sql b/policies/queries/codebuild/check_oauth_usage_for_sources.sql new file mode 100644 index 000000000..57eda8cee --- /dev/null +++ b/policies/queries/codebuild/check_oauth_usage_for_sources.sql @@ -0,0 +1,16 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'CodeBuild GitHub or Bitbucket source repository URLs should use OAuth' as title, + account_id, + arn as resource_id, + case when + ( + source_type = 'GITHUB' or source_type = 'BITBUCKET' + ) and source_auth_type != 'OAUTH' + then 'fail' + else 'pass' + end as status +from aws_codebuild_projects diff --git a/policies/queries/config/enabled_all_regions.sql b/policies/queries/config/enabled_all_regions.sql new file mode 100644 index 000000000..57c916b2e --- /dev/null +++ b/policies/queries/config/enabled_all_regions.sql @@ -0,0 +1,18 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'AWS Config should be enabled' as title, + account_id, + arn as resource_id, + case when + recording_group_include_global_resource_types IS NOT TRUE + OR recording_group_all_supported IS NOT TRUE + OR status_recording IS NOT TRUE + OR status_last_status IS DISTINCT FROM 'SUCCESS' + then 'fail' + else 'pass' + end as status +FROM + aws_config_configuration_recorders diff --git a/policies/queries/dms/replication_not_public.sql b/policies/queries/dms/replication_not_public.sql new file mode 100644 index 000000000..963872b7e --- /dev/null +++ b/policies/queries/dms/replication_not_public.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'AWS Database Migration Service replication instances should not be public' as title, + account_id, + arn as resource_id, + case when + publicly_accessible is true + then 'fail' + else 'pass' + end as status +from aws_dms_replication_instances diff --git a/policies/queries/dynamodb/autoscale_or_ondemand.sql b/policies/queries/dynamodb/autoscale_or_ondemand.sql new file mode 100644 index 000000000..3b3b92858 --- /dev/null +++ b/policies/queries/dynamodb/autoscale_or_ondemand.sql @@ -0,0 +1,32 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'DynamoDB tables should automatically scale capacity with demand' as title, + t.account_id, + pr.arn as resource_id, + case when + (t.billing_mode_summary -> 'billing_mode')::VARCHAR IS DISTINCT + FROM 'PAY_PER_REQUEST' + AND ( + s.read_capacity -> 'auto_scaling_disabled' IS NULL + OR (s.read_capacity -> 'auto_scaling_disabled') IS DISTINCT FROM 'false' + OR s.write_capacity -> 'auto_scaling_disabled' IS NULL + OR (s.write_capacity -> 'auto_scaling_disabled') IS DISTINCT + FROM 'false' + ) + AND (pr.cq_id IS NULL OR pw.cq_id IS NULL) + then 'fail' + else 'pass' + end as status +FROM aws_dynamodb_tables t + LEFT JOIN aws_dynamodb_table_replica_auto_scalings s ON s.table_cq_id = t.cq_id + LEFT JOIN aws_applicationautoscaling_policies pr ON (pr.namespace = 'dynamodb' + AND pr.resource_id = CONCAT('table/', t.name) + AND pr.type = 'TargetTrackingScaling' + AND pr.scalable_dimension = 'dynamodb:table:ReadCapacityUnits') + LEFT JOIN aws_applicationautoscaling_policies pw ON (pw.namespace = 'dynamodb' + AND pw.resource_id = CONCAT('table/', t.name) + AND pw.type = 'TargetTrackingScaling' + AND pw.scalable_dimension = 'dynamodb:table:WriteCapacityUnits') diff --git a/policies/queries/dynamodb/dax_encrypted_at_rest.sql b/policies/queries/dynamodb/dax_encrypted_at_rest.sql new file mode 100644 index 000000000..71b6647a9 --- /dev/null +++ b/policies/queries/dynamodb/dax_encrypted_at_rest.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'DynamoDB Accelerator (DAX) clusters should be encrypted at rest' as title, + account_id, + arn as resource_id, + case when + sse_description_status is distinct from 'ENABLED' + then 'fail' + else 'pass' + end as status +from aws_dax_clusters diff --git a/policies/queries/dynamodb/point_in_time_recovery.sql b/policies/queries/dynamodb/point_in_time_recovery.sql new file mode 100644 index 000000000..2a08851ed --- /dev/null +++ b/policies/queries/dynamodb/point_in_time_recovery.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'DynamoDB tables should have point-in-time recovery enabled' as title, + t.account_id, + t.arn as resource_id, + case when + b.point_in_time_recovery_status is distinct from 'ENABLED' + then 'fail' + else 'pass' + end as status +FROM aws_dynamodb_tables t + LEFT JOIN aws_dynamodb_table_continuous_backups b ON b.table_cq_id = t.cq_id diff --git a/policies/queries/ec2/default_sg_no_access.sql b/policies/queries/ec2/default_sg_no_access.sql new file mode 100644 index 000000000..f7c51f13f --- /dev/null +++ b/policies/queries/ec2/default_sg_no_access.sql @@ -0,0 +1,19 @@ +insert into aws_policy_results +select + :execution_time, + :'framework', + :'check_id', + 'The VPC default security group should not allow inbound and outbound traffic', + account_id, + arn, + case when + group_name = 'default' + then 'fail' + else 'pass' + end +from + aws_ec2_security_groups +inner join + aws_ec2_security_group_ip_permissions on + aws_ec2_security_groups.cq_id + = aws_ec2_security_group_ip_permissions.security_group_cq_id diff --git a/policies/queries/ec2/ebs_encryption_by_default_disabled.sql b/policies/queries/ec2/ebs_encryption_by_default_disabled.sql new file mode 100644 index 000000000..bb37a2b49 --- /dev/null +++ b/policies/queries/ec2/ebs_encryption_by_default_disabled.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'EBS default encryption should be enabled' as title, + account_id, + concat(account_id,':',region) as resource_id, + case when + ebs_encryption_enabled_by_default is distinct from true + then 'fail' + else 'pass' + end as status +from aws_ec2_regional_config diff --git a/policies/queries/ec2/ebs_snapshot_permissions_check.sql b/policies/queries/ec2/ebs_snapshot_permissions_check.sql new file mode 100644 index 000000000..16bfb8f3d --- /dev/null +++ b/policies/queries/ec2/ebs_snapshot_permissions_check.sql @@ -0,0 +1,25 @@ +insert into aws_policy_results +WITH snapshot_access_groups AS ( + SELECT account_id, + region, + snapshot_id, + JSONB_ARRAY_ELEMENTS(create_volume_permissions) ->> 'group' AS "group", + JSONB_ARRAY_ELEMENTS(create_volume_permissions) ->> 'user_id' AS user_id + FROM aws_ec2_ebs_snapshots +) +SELECT DISTINCT + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Amazon EBS snapshots should not be public, determined by the ability to be restorable by anyone' as title, + account_id, + snapshot_id as resource_id, + case when + "group" = 'all' + -- this is under question because + -- trusted accounts(user_id) do not violate this control + OR user_id IS DISTINCT FROM '' + then 'pass' + else 'fail' + end as status +FROM snapshot_access_groups \ No newline at end of file diff --git a/policies/queries/ec2/flow_logs_enabled_in_all_vpcs.sql b/policies/queries/ec2/flow_logs_enabled_in_all_vpcs.sql new file mode 100644 index 000000000..dd86c304f --- /dev/null +++ b/policies/queries/ec2/flow_logs_enabled_in_all_vpcs.sql @@ -0,0 +1,16 @@ +insert into aws_policy_results +select + :execution_time, + :'framework', + :'check_id', + 'VPC flow logging should be enabled in all VPCs', + aws_ec2_vpcs.account_id, + aws_ec2_vpcs.arn, + case when + aws_ec2_flow_logs.resource_id is null + then 'fail' + else 'pass' + end +from aws_ec2_vpcs +left join aws_ec2_flow_logs on + aws_ec2_vpcs.id = aws_ec2_flow_logs.resource_id diff --git a/policies/queries/ec2/get_unused_public_ips.sql b/policies/queries/ec2/get_unused_public_ips.sql new file mode 100644 index 000000000..095a15118 --- /dev/null +++ b/policies/queries/ec2/get_unused_public_ips.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Unused EC2 EIPs should be removed' as title, + account_id, + public_ip as resource_id, + case when + instance_id is null + then 'fail' + else 'pass' + end as status +from aws_ec2_eips diff --git a/policies/queries/ec2/instances_with_more_than_2_network_interfaces.sql b/policies/queries/ec2/instances_with_more_than_2_network_interfaces.sql new file mode 100644 index 000000000..404ec812f --- /dev/null +++ b/policies/queries/ec2/instances_with_more_than_2_network_interfaces.sql @@ -0,0 +1,20 @@ +insert into aws_policy_results +with data as ( + select account_id, id, COUNT(aws_ec2_instance_network_interfaces.cq_id) as cnt + from aws_ec2_instances +left join + aws_ec2_instance_network_interfaces on + aws_ec2_instances.cq_id = aws_ec2_instance_network_interfaces.instance_cq_id +group by account_id, + region, + id +) +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'EC2 instances should not use multiple ENIs' as title, + account_id, + id as resource_id, + case when cnt > 1 then 'fail' else 'pass' end as status +from data diff --git a/policies/queries/ec2/instances_with_public_ip.sql b/policies/queries/ec2/instances_with_public_ip.sql new file mode 100644 index 000000000..a94b48dce --- /dev/null +++ b/policies/queries/ec2/instances_with_public_ip.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'EC2 instances should not have a public IP address' as title, + account_id, + id as resource_id, + case when + public_ip_address is not null + then 'fail' + else 'pass' + end as status +from aws_ec2_instances diff --git a/policies/queries/ec2/no_broad_public_ingress_on_port_22.sql b/policies/queries/ec2/no_broad_public_ingress_on_port_22.sql new file mode 100644 index 000000000..6172bc0a6 --- /dev/null +++ b/policies/queries/ec2/no_broad_public_ingress_on_port_22.sql @@ -0,0 +1,18 @@ +-- uses view which uses aws_security_group_ingress_rules.sql query +insert into aws_policy_results +select + :execution_time, + :'framework', + :'check_id', + 'Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored)', + account_id, + arn, + case when + (ip = '0.0.0.0/0' or ip = '::/0') + and ( + (from_port is null and to_port is null) -- all ports + or 22 between from_port and to_port) + then 'fail' + else 'pass' + end +from view_aws_security_group_ingress_rules diff --git a/policies/queries/ec2/no_broad_public_ingress_on_port_3389.sql b/policies/queries/ec2/no_broad_public_ingress_on_port_3389.sql new file mode 100644 index 000000000..f53ce7e7e --- /dev/null +++ b/policies/queries/ec2/no_broad_public_ingress_on_port_3389.sql @@ -0,0 +1,18 @@ +-- uses view which uses aws_security_group_ingress_rules.sql query +insert into aws_policy_results +select + :execution_time, + :'framework', + :'check_id', + 'Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored)', + account_id, + arn, + case when + (ip = '0.0.0.0/0' or ip = '::/0') + and ( + (from_port is null and to_port is null) -- all ports + or 3389 between from_port and to_port + ) then 'fail' + else 'pass' + end +from view_aws_security_group_ingress_rules diff --git a/policies/queries/ec2/no_unsued_security_groups.sql b/policies/queries/ec2/no_unsued_security_groups.sql new file mode 100644 index 000000000..58aabaf71 --- /dev/null +++ b/policies/queries/ec2/no_unsued_security_groups.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'security group is not currently in use so it should be deleted' as title, + account_id, + arn as resource_id, + case when aws_ec2_instance_network_interface_groups.cq_id is null then 'fail' else 'pass' end as status +from + aws_ec2_security_groups +left join + aws_ec2_instance_network_interface_groups on + aws_ec2_security_groups.id = aws_ec2_instance_network_interface_groups.group_id diff --git a/policies/queries/ec2/not_imdsv2_instances.sql b/policies/queries/ec2/not_imdsv2_instances.sql new file mode 100644 index 000000000..305861352 --- /dev/null +++ b/policies/queries/ec2/not_imdsv2_instances.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'EC2 instances should use IMDSv2' as title, + account_id, + id as resource_id, + case when + metadata_options_http_tokens is distinct from 'required' + then 'fail' + else 'pass' + end as status +from aws_ec2_instances diff --git a/policies/queries/ec2/public_egress_sg_and_routing_instances.sql b/policies/queries/ec2/public_egress_sg_and_routing_instances.sql new file mode 100644 index 000000000..f1c2491f4 --- /dev/null +++ b/policies/queries/ec2/public_egress_sg_and_routing_instances.sql @@ -0,0 +1,30 @@ +insert into aws_policy_results +-- Find all AWS instances that are in a subnet that includes a catchall route +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Find all ec2 instances that have unrestricted access to the internet with a wide open security group and routing' as title, + account_id, + id as resource_id, + 'fail' as status -- TODO FIXME +from aws_ec2_instances +where subnet_id in + -- Find all subnets that include a route table that inclues a catchall route + (select subnet_id + from aws_ec2_route_tables + inner join + aws_ec2_route_table_associations on + aws_ec2_route_table_associations.route_table_cq_id = aws_ec2_route_tables.cq_id + where aws_ec2_route_tables.cq_id in + -- Find all routes in any route table that contains a route to 0.0.0.0/0 or ::/0 + (select route_table_cq_id + from aws_ec2_route_table_routes + where destination_cidr_block = '0.0.0.0/0' + or destination_ipv6_cidr_block = '::/0')) + and cq_id in + -- Find all instances that have egress rule that allows access to all ip addresses + (select instance_cq_id + from aws_ec2_instance_security_groups + inner join view_aws_security_group_egress_rules on group_id = id + where (ip = '0.0.0.0/0' or ip = '::/0')) diff --git a/policies/queries/ec2/public_egress_sg_instances.sql b/policies/queries/ec2/public_egress_sg_instances.sql new file mode 100644 index 000000000..8896c907d --- /dev/null +++ b/policies/queries/ec2/public_egress_sg_instances.sql @@ -0,0 +1,17 @@ +insert into aws_policy_results +-- Find all AWS instances that have a security group that allows unrestricted egress +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'All ec2 instances that have unrestricted access to the internet via a security group' as title, + account_id, + id as resource_id, + 'fail' as status -- TODO FIXME +from aws_ec2_instances +where cq_id in + -- Find all instances that have egress rule that allows access to all ip addresses + (select instance_cq_id + from aws_ec2_instance_security_groups + inner join view_aws_security_group_egress_rules on group_id = id + where (ip = '0.0.0.0/0' or ip = '::/0')) diff --git a/policies/queries/ec2/public_ips.sql b/policies/queries/ec2/public_ips.sql new file mode 100644 index 000000000..c0eae2a36 --- /dev/null +++ b/policies/queries/ec2/public_ips.sql @@ -0,0 +1,11 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Find all instances with a public IP address' AS title, + account_id, + arn as resource_id, + case when public_ip_address is not null then 'fail' else 'pass' end as status +from + aws_ec2_instances diff --git a/policies/queries/ec2/security_groups_with_access_to_unauthorized_ports.sql b/policies/queries/ec2/security_groups_with_access_to_unauthorized_ports.sql new file mode 100644 index 000000000..cec3ead22 --- /dev/null +++ b/policies/queries/ec2/security_groups_with_access_to_unauthorized_ports.sql @@ -0,0 +1,20 @@ +-- uses view which uses aws_security_group_ingress_rules.sql query +insert into aws_policy_results +SELECT + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Aggregates rules of security groups with ports and IPs including ipv6' as title, + account_id, + id as resource_id, + case when + (ip = '0.0.0.0/0' OR ip = '::/0') + AND (from_port IS NULL AND to_port IS NULL) -- all prots + OR from_port IS DISTINCT FROM 80 + OR to_port IS DISTINCT FROM 80 + OR from_port IS DISTINCT FROM 443 + OR to_port IS DISTINCT FROM 443 + then 'fail' + else 'pass' + end +FROM view_aws_security_group_ingress_rules diff --git a/policies/queries/ec2/security_groups_with_open_critical_ports.sql b/policies/queries/ec2/security_groups_with_open_critical_ports.sql new file mode 100644 index 000000000..beaa3b09c --- /dev/null +++ b/policies/queries/ec2/security_groups_with_open_critical_ports.sql @@ -0,0 +1,40 @@ +-- uses view which uses aws_security_group_ingress_rules.sql query +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Security groups should not allow unrestricted access to ports with high risk' as title, + account_id, + id as resource_id, + case when + (ip = '0.0.0.0/0' or ip = '::/0') + and (from_port is null and to_port is null) -- all prots + or 20 between from_port and to_port + or 21 between from_port and to_port + or 22 between from_port and to_port + or 23 between from_port and to_port + or 25 between from_port and to_port + or 110 between from_port and to_port + or 135 between from_port and to_port + or 143 between from_port and to_port + or 445 between from_port and to_port + or 1433 between from_port and to_port + or 1434 between from_port and to_port + or 3000 between from_port and to_port + or 3306 between from_port and to_port + or 3389 between from_port and to_port + or 4333 between from_port and to_port + or 5000 between from_port and to_port + or 5432 between from_port and to_port + or 5500 between from_port and to_port + or 5601 between from_port and to_port + or 8080 between from_port and to_port + or 8088 between from_port and to_port + or 8888 between from_port and to_port + or 9200 between from_port and to_port + or 9300 between from_port and to_port + then 'fail' + else 'pass' + end +from view_aws_security_group_ingress_rules diff --git a/policies/queries/ec2/sgs_all_access_to_port_22.sql b/policies/queries/ec2/sgs_all_access_to_port_22.sql new file mode 100644 index 000000000..83cf2cc1d --- /dev/null +++ b/policies/queries/ec2/sgs_all_access_to_port_22.sql @@ -0,0 +1,81 @@ +-- TODO FIXME +/* Find Security groups that give access to ipv4 addresses */ +select t.arn +from ( + select + /* create arn for sg */ + arn, + /* Calculate total number of IPs a SG rule gives access to */ + ( + SPLIT_PART( + HOST(BROADCAST(cidr::CIDR)), '.', 1 + )::BIGINT * 16777216 + + SPLIT_PART(HOST(BROADCAST(cidr::CIDR)), '.', 2)::BIGINT * 65536 + + SPLIT_PART(HOST(BROADCAST(cidr::CIDR)), '.', 3)::BIGINT * 256 + + SPLIT_PART(HOST(BROADCAST(cidr::CIDR)), '.', 4)::BIGINT + ) - ( + SPLIT_PART(HOST(cidr::CIDR), '.', 1)::BIGINT * 16777216 + + SPLIT_PART(HOST(cidr::CIDR), '.', 2)::BIGINT * 65536 + + SPLIT_PART(HOST(cidr::CIDR), '.', 3)::BIGINT * 256 + + SPLIT_PART(HOST(cidr::CIDR), '.', 4)::BIGINT + ) as totalips + from aws_ec2_security_groups + inner join + aws_ec2_security_group_ip_permissions on + aws_ec2_security_groups.cq_id + = aws_ec2_security_group_ip_permissions.security_group_cq_id + inner join + aws_ec2_security_group_ip_permission_ip_ranges on + aws_ec2_security_group_ip_permissions.cq_id + = aws_ec2_security_group_ip_permission_ip_ranges.security_group_ip_permission_cq_id + and aws_ec2_security_group_ip_permission_ip_ranges.cidr_type='ipv4' + where ( + ( + from_port is null + and to_port is null + ) + or 22 between from_port + and to_port + ) +) as t +group by t.arn +having SUM(t.totalips) = 4294967295 +/* this value is the total number of ips in ipv4 space ie 0.0.0.0/0 */ +union +/* Find Security groups that give access to ipv6 addresses */ +select t.arn +from ( + select + /* create arn for sg */ + arn, + /* Calculate total number of IPs a SG rule gives access to */ + ROUND( + 2 ^ ( + 128 - MASKLEN( + aws_ec2_security_group_ip_permission_ip_ranges.cidr::CIDR + ) + )::NUMERIC + ) as totalips + from aws_ec2_security_groups + inner join + aws_ec2_security_group_ip_permissions on + aws_ec2_security_groups.cq_id + = aws_ec2_security_group_ip_permissions.security_group_cq_id + inner join + aws_ec2_security_group_ip_permission_ip_ranges on + aws_ec2_security_group_ip_permissions.cq_id + = aws_ec2_security_group_ip_permission_ip_ranges.security_group_ip_permission_cq_id + and aws_ec2_security_group_ip_permission_ip_ranges.cidr_type='ipv6' + where ( + ( + from_port is null + and to_port is null + ) + or 22 between from_port + and to_port + ) + ) as t +group by t.arn +having SUM(t.totalips) = 340282366920938463463374607431768211456; + +/* this value is the total number of ips in ipv6 space ie ::/0 */ diff --git a/policies/queries/ec2/stopped_more_thant_30_days_ago_instances.sql b/policies/queries/ec2/stopped_more_thant_30_days_ago_instances.sql new file mode 100644 index 000000000..d5dcb4738 --- /dev/null +++ b/policies/queries/ec2/stopped_more_thant_30_days_ago_instances.sql @@ -0,0 +1,16 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Stopped EC2 instances should be removed after a specified time period' as title, + account_id, + id as resource_id, + case when + state_name = 'stopped' + AND NOW() - state_transition_reason_time > + INTERVAL '30' DAY + then 'fail' + else 'pass' + end +from aws_ec2_instances diff --git a/policies/queries/ec2/subnets_that_assign_public_ips.sql b/policies/queries/ec2/subnets_that_assign_public_ips.sql new file mode 100644 index 000000000..186385779 --- /dev/null +++ b/policies/queries/ec2/subnets_that_assign_public_ips.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'EC2 subnets should not automatically assign public IP addresses' as title, + account_id, + arn as resource_id, + case when + map_public_ip_on_launch is true + then 'fail' + else 'pass' + end +from aws_ec2_subnets diff --git a/policies/queries/ec2/unencrypted_ebs_volumes.sql b/policies/queries/ec2/unencrypted_ebs_volumes.sql new file mode 100644 index 000000000..3ca4786ec --- /dev/null +++ b/policies/queries/ec2/unencrypted_ebs_volumes.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Attached EBS volumes should be encrypted at rest' as title, + account_id, + arn as resource_id, + case when + encrypted is FALSE + then 'fail' + else 'pass' + end as status +from aws_ec2_ebs_volumes diff --git a/policies/queries/ec2/unused_acls.sql b/policies/queries/ec2/unused_acls.sql new file mode 100644 index 000000000..71ab86e80 --- /dev/null +++ b/policies/queries/ec2/unused_acls.sql @@ -0,0 +1,17 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Unused network access control lists should be removed' as title, + account_id, + id as resource_id, + case when + aws_ec2_network_acl_associations.cq_id is null + then 'pass' + else 'fail' + end as status +from aws_ec2_network_acls + left join + aws_ec2_network_acl_associations on + aws_ec2_network_acls.cq_id = aws_ec2_network_acl_associations.network_acl_cq_id diff --git a/policies/queries/ec2/vpcs_without_ec2_endpoint.sql b/policies/queries/ec2/vpcs_without_ec2_endpoint.sql new file mode 100644 index 000000000..29e715273 --- /dev/null +++ b/policies/queries/ec2/vpcs_without_ec2_endpoint.sql @@ -0,0 +1,25 @@ +insert into aws_policy_results +with endpoints as ( + select vpc_id + from aws_ec2_vpc_endpoints + where vpc_endpoint_type = 'Interface' + and service_name ~ CONCAT( + 'com.amazonaws.', region, '.ec2' + ) +) + +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Amazon EC2 should be configured to use VPC endpoints that are created for the Amazon EC2 service' as title, + account_id, + id as resource_id, + case when + endpoints.vpc_id is null + then 'fail' + else 'pass' + end as status +from aws_ec2_vpcs +left join endpoints + on aws_ec2_vpcs.id = endpoints.vpc_id diff --git a/policies/queries/ecs/ecs_services_with_public_ips.sql b/policies/queries/ecs/ecs_services_with_public_ips.sql new file mode 100644 index 000000000..1525721f2 --- /dev/null +++ b/policies/queries/ecs/ecs_services_with_public_ips.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Amazon ECS services should not have public IP addresses assigned to them automatically' as title, + account_id, + s.arn as resource_id, + case when + network_configuration_awsvpc_configuration_assign_public_ip is distinct from 'DISABLED' + then 'fail' + else 'pass' + end as status +from aws_ecs_clusters c + left join aws_ecs_cluster_services s ON c.cq_id = s.cluster_cq_id diff --git a/policies/queries/ecs/task_definitions_secure_networking.sql b/policies/queries/ecs/task_definitions_secure_networking.sql new file mode 100644 index 000000000..df28340be --- /dev/null +++ b/policies/queries/ecs/task_definitions_secure_networking.sql @@ -0,0 +1,23 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Amazon ECS task definitions should have secure networking modes and user definitions' as title, + account_id, + aws_ecs_task_definitions.arn as resource_id, + case when + aws_ecs_task_definitions.network_mode = 'host' + and ( + aws_ecs_task_definition_container_definitions.privileged is distinct from TRUE + and ( + aws_ecs_task_definition_container_definitions."user" = 'root' or aws_ecs_task_definition_container_definitions."user" is null + ) + ) + then 'fail' + else 'pass' + end as status +from aws_ecs_task_definitions + inner join + aws_ecs_task_definition_container_definitions on + aws_ecs_task_definitions.cq_id = aws_ecs_task_definition_container_definitions.task_definition_cq_id diff --git a/policies/queries/efs/efs_filesystems_with_disabled_backups.sql b/policies/queries/efs/efs_filesystems_with_disabled_backups.sql new file mode 100644 index 000000000..8fac229a3 --- /dev/null +++ b/policies/queries/efs/efs_filesystems_with_disabled_backups.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Amazon EFS volumes should be in backup plans' as title, + account_id, + arn as resource_id, + case when + backup_policy_status is distinct from 'ENABLED' + then 'fail' + else 'pass' + end as status +from aws_efs_filesystems diff --git a/policies/queries/efs/unencrypted_efs_filesystems.sql b/policies/queries/efs/unencrypted_efs_filesystems.sql new file mode 100644 index 000000000..37e9a2e59 --- /dev/null +++ b/policies/queries/efs/unencrypted_efs_filesystems.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Amazon EFS should be configured to encrypt file data at rest using AWS KMS' as title, + account_id, + arn as resource_id, + case when + encrypted is distinct from TRUE + or kms_key_id is null + then 'fail' + else 'pass' + end as status +from aws_efs_filesystems diff --git a/policies/queries/elasticbeanstalk/advanced_health_reporting_enabled.sql b/policies/queries/elasticbeanstalk/advanced_health_reporting_enabled.sql new file mode 100644 index 000000000..456da76ac --- /dev/null +++ b/policies/queries/elasticbeanstalk/advanced_health_reporting_enabled.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Elastic Beanstalk environments should have enhanced health reporting enabled' as title, + account_id, + arn as resource_id, + case when + health_status is null + or health is null + then 'fail' + else 'pass' + end as status +from aws_elasticbeanstalk_environments diff --git a/policies/queries/elasticbeanstalk/elastic_beanstalk_managed_updates_enabled.sql b/policies/queries/elasticbeanstalk/elastic_beanstalk_managed_updates_enabled.sql new file mode 100644 index 000000000..f81076f1f --- /dev/null +++ b/policies/queries/elasticbeanstalk/elastic_beanstalk_managed_updates_enabled.sql @@ -0,0 +1,24 @@ +insert into aws_policy_results +SELECT + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Elastic Beanstalk managed platform updates should be enabled' as title, + aws_elasticbeanstalk_environments.account_id, + aws_elasticbeanstalk_configuration_settings.application_arn as resource_id, + case when + option_name = 'ManagedActionsEnabled' + and value::boolean is distinct + from true + then 'fail' + else 'pass' + end as status +from aws_elasticbeanstalk_configuration_setting_options + left join + aws_elasticbeanstalk_configuration_settings on + aws_elasticbeanstalk_configuration_setting_options.configuration_setting_cq_id = + aws_elasticbeanstalk_configuration_settings.cq_id + left join + aws_elasticbeanstalk_environments on + aws_elasticbeanstalk_configuration_settings.environment_cq_id = + aws_elasticbeanstalk_environments.cq_id diff --git a/policies/queries/elasticsearch/connections_to_elasticsearch_domains_should_be_encrypted_using_tls_1_2.sql b/policies/queries/elasticsearch/connections_to_elasticsearch_domains_should_be_encrypted_using_tls_1_2.sql new file mode 100644 index 000000000..93f75ba03 --- /dev/null +++ b/policies/queries/elasticsearch/connections_to_elasticsearch_domains_should_be_encrypted_using_tls_1_2.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Connections to Elasticsearch domains should be encrypted using TLS 1.2' as title, + account_id, + arn as resource_id, + case when + domain_endpoint_tls_security_policy is distinct from 'Policy-Min-TLS-1-2-2019-07' + then 'fail' + else 'pass' + end as status +from aws_elasticsearch_domains diff --git a/policies/queries/elasticsearch/elasticsearch_domain_error_logging_to_cloudwatch_logs_should_be_enabled.sql b/policies/queries/elasticsearch/elasticsearch_domain_error_logging_to_cloudwatch_logs_should_be_enabled.sql new file mode 100644 index 000000000..d0793b1b6 --- /dev/null +++ b/policies/queries/elasticsearch/elasticsearch_domain_error_logging_to_cloudwatch_logs_should_be_enabled.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +SELECT + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Elasticsearch domain error logging to CloudWatch Logs should be enabled' as title, + account_id, + arn as resource_id, + case when + log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' IS DISTINCT FROM 'true' + OR log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NULL + then 'fail' + else 'pass' + end as status +FROM aws_elasticsearch_domains diff --git a/policies/queries/elasticsearch/elasticsearch_domains_should_be_configured_with_at_least_three_dedicated_master_nodes.sql b/policies/queries/elasticsearch/elasticsearch_domains_should_be_configured_with_at_least_three_dedicated_master_nodes.sql new file mode 100644 index 000000000..aa97be575 --- /dev/null +++ b/policies/queries/elasticsearch/elasticsearch_domains_should_be_configured_with_at_least_three_dedicated_master_nodes.sql @@ -0,0 +1,16 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Elasticsearch domains should be configured with at least three dedicated master nodes' as title, + account_id, + arn as resource_id, + case when + cluster_dedicated_master_enabled is not TRUE + or cluster_dedicated_master_count is null + or cluster_dedicated_master_count < 3 + then 'fail' + else 'pass' + end as status +from aws_elasticsearch_domains diff --git a/policies/queries/elasticsearch/elasticsearch_domains_should_be_in_vpc.sql b/policies/queries/elasticsearch/elasticsearch_domains_should_be_in_vpc.sql new file mode 100644 index 000000000..b947ee5ea --- /dev/null +++ b/policies/queries/elasticsearch/elasticsearch_domains_should_be_in_vpc.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Elasticsearch domains should be in a VPC' as title, + account_id, + arn as resource_id, + case when + vpc_vpc_id is null + then 'fail' + else 'pass' + end as status +from aws_elasticsearch_domains diff --git a/policies/queries/elasticsearch/elasticsearch_domains_should_encrypt_data_sent_between_nodes.sql b/policies/queries/elasticsearch/elasticsearch_domains_should_encrypt_data_sent_between_nodes.sql new file mode 100644 index 000000000..140ed0ba3 --- /dev/null +++ b/policies/queries/elasticsearch/elasticsearch_domains_should_encrypt_data_sent_between_nodes.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Elasticsearch domains should encrypt data sent between nodes' as title, + account_id, + arn as resource_id, + case when + node_to_node_encryption_enabled is not true + then 'fail' + else 'pass' + end as status +from aws_elasticsearch_domains diff --git a/policies/queries/elasticsearch/elasticsearch_domains_should_have_at_least_three_data_nodes.sql b/policies/queries/elasticsearch/elasticsearch_domains_should_have_at_least_three_data_nodes.sql new file mode 100644 index 000000000..9eb2c30e0 --- /dev/null +++ b/policies/queries/elasticsearch/elasticsearch_domains_should_have_at_least_three_data_nodes.sql @@ -0,0 +1,16 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Elasticsearch domains should have at least three data nodes' as title, + account_id, + arn as resource_id, + case when + not cluster_zone_awareness_enabled + or cluster_instance_count is null + or cluster_instance_count < 3 + then 'fail' + else 'pass' + end as status +from aws_elasticsearch_domains diff --git a/policies/queries/elasticsearch/elasticsearch_domains_should_have_audit_logging_enabled.sql b/policies/queries/elasticsearch/elasticsearch_domains_should_have_audit_logging_enabled.sql new file mode 100644 index 000000000..c5e8658c2 --- /dev/null +++ b/policies/queries/elasticsearch/elasticsearch_domains_should_have_audit_logging_enabled.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Elasticsearch domains should have audit logging enabled' as title, + account_id, + arn as resource_id, + case when + log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' is distinct from 'true' + or log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' is null + then 'fail' + else 'pass' + end as status +from aws_elasticsearch_domains diff --git a/policies/queries/elasticsearch/elasticsearch_domains_should_have_encryption_at_rest_enabled.sql b/policies/queries/elasticsearch/elasticsearch_domains_should_have_encryption_at_rest_enabled.sql new file mode 100644 index 000000000..d136572de --- /dev/null +++ b/policies/queries/elasticsearch/elasticsearch_domains_should_have_encryption_at_rest_enabled.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Elasticsearch domains should have encryption at rest enabled' as title, + account_id, + arn as resource_id, + case when + encryption_at_rest_enabled is not true + then 'fail' + else 'pass' + end as status +from aws_elasticsearch_domains diff --git a/policies/queries/elb/alb_deletion_protection_enabled.sql b/policies/queries/elb/alb_deletion_protection_enabled.sql new file mode 100644 index 000000000..cccaa2de9 --- /dev/null +++ b/policies/queries/elb/alb_deletion_protection_enabled.sql @@ -0,0 +1,17 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Application Load Balancer deletion protection should be enabled' as title, + account_id, + arn as resource_id, + case when + aws_elbv2_load_balancers.type = 'application' and aws_elbv2_load_balancer_attributes.deletion_protection is not true + then 'fail' + else 'pass' + end as status +from aws_elbv2_load_balancers +inner join + aws_elbv2_load_balancer_attributes on + aws_elbv2_load_balancer_attributes.load_balancer_cq_id = aws_elbv2_load_balancers.cq_id diff --git a/policies/queries/elb/alb_drop_http_headers.sql b/policies/queries/elb/alb_drop_http_headers.sql new file mode 100644 index 000000000..4ce5232d1 --- /dev/null +++ b/policies/queries/elb/alb_drop_http_headers.sql @@ -0,0 +1,17 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Application load balancers should be configured to drop HTTP headers' as title, + account_id, + arn as resource_id, + case when + aws_elbv2_load_balancers.type = 'application' and aws_elbv2_load_balancer_attributes.routing_http_drop_invalid_header_fields is not true + then 'fail' + else 'pass' + end as status +from aws_elbv2_load_balancers +inner join + aws_elbv2_load_balancer_attributes on + aws_elbv2_load_balancer_attributes.load_balancer_cq_id = aws_elbv2_load_balancers.cq_id diff --git a/policies/queries/elb/alb_logging_enabled.sql b/policies/queries/elb/alb_logging_enabled.sql new file mode 100644 index 000000000..35bcf1e4f --- /dev/null +++ b/policies/queries/elb/alb_logging_enabled.sql @@ -0,0 +1,34 @@ +insert into aws_policy_results +(select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Application and Classic Load Balancers logging should be enabled' as title, + account_id, + arn as resource_id, + case when + aws_elbv2_load_balancers.type = 'application' and aws_elbv2_load_balancer_attributes.access_logs_s3_enabled is not true + then 'fail' + else 'pass' + end as status + from aws_elbv2_load_balancers + inner join + aws_elbv2_load_balancer_attributes on + aws_elbv2_load_balancer_attributes.load_balancer_cq_id = aws_elbv2_load_balancers.cq_id) +union +( + select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Application and Classic Load Balancers logging should be enabled' as title, + account_id, + arn as resource_id, + case when + attributes_access_log_enabled is not true + then 'fail' + else 'pass' + end as status + from + aws_elbv1_load_balancers +) diff --git a/policies/queries/elb/elbv1_cert_provided_by_acm.sql b/policies/queries/elb/elbv1_cert_provided_by_acm.sql new file mode 100644 index 000000000..3976e934a --- /dev/null +++ b/policies/queries/elb/elbv1_cert_provided_by_acm.sql @@ -0,0 +1,20 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Classic Load Balancers with SSL/HTTPS listeners should use a certificate provided by AWS Certificate Manager' as title, + aws_elbv1_load_balancers.account_id, + aws_elbv1_load_balancers.arn as resource_id, + case when + aws_elbv1_load_balancer_listeners.listener_protocol = 'HTTPS' and aws_acm_certificates.arn is null + then 'fail' + else 'pass' + end as status +from aws_elbv1_load_balancers +inner join + aws_elbv1_load_balancer_listeners on + aws_elbv1_load_balancer_listeners.load_balancer_cq_id = aws_elbv1_load_balancers.cq_id +left join + aws_acm_certificates on + aws_acm_certificates.arn = aws_elbv1_load_balancer_listeners.listener_ssl_certificate_id diff --git a/policies/queries/elb/elbv1_conn_draining_enabled.sql b/policies/queries/elb/elbv1_conn_draining_enabled.sql new file mode 100644 index 000000000..0ddb507ec --- /dev/null +++ b/policies/queries/elb/elbv1_conn_draining_enabled.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Classic Load Balancers should have connection draining enabled' as title, + account_id, + aws_elbv1_load_balancers.arn as resource_id, + case when + attributes_connection_draining_enabled is not true + then 'fail' + else 'pass' + end as status +from + aws_elbv1_load_balancers diff --git a/policies/queries/elb/elbv1_https_or_tls.sql b/policies/queries/elb/elbv1_https_or_tls.sql new file mode 100644 index 000000000..1fc0ebcf3 --- /dev/null +++ b/policies/queries/elb/elbv1_https_or_tls.sql @@ -0,0 +1,17 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Classic Load Balancer listeners should be configured with HTTPS or TLS termination' as title, + aws_elbv1_load_balancers.account_id, + aws_elbv1_load_balancers.arn as resource_id, + case when + aws_elbv1_load_balancer_listeners.listener_protocol not in ('HTTPS', 'SSL') + then 'fail' + else 'pass' + end as status +from aws_elbv1_load_balancers +inner join + aws_elbv1_load_balancer_listeners on + aws_elbv1_load_balancer_listeners.load_balancer_cq_id = aws_elbv1_load_balancers.cq_id diff --git a/policies/queries/elb/elbv1_https_predefined_policy.sql b/policies/queries/elb/elbv1_https_predefined_policy.sql new file mode 100644 index 000000000..7dca96c1e --- /dev/null +++ b/policies/queries/elb/elbv1_https_predefined_policy.sql @@ -0,0 +1,19 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Classic Load Balancers with HTTPS/SSL listeners should use a predefined security policy that has strong configuration' as title, + aws_elbv1_load_balancers.account_id, + aws_elbv1_load_balancers.arn as resource_id, + case when + aws_elbv1_load_balancer_listeners.listener_protocol in ('HTTPS', 'SSL') + and 'ELBSecurityPolicy-TLS-1-2-2017-01' != any( + aws_elbv1_load_balancers.other_policies) + then 'fail' + else 'pass' + end as status +from aws_elbv1_load_balancers +inner join + aws_elbv1_load_balancer_listeners on + aws_elbv1_load_balancer_listeners.load_balancer_cq_id = aws_elbv1_load_balancers.cq_id diff --git a/policies/queries/elb/elbv1_internet_facing.sql b/policies/queries/elb/elbv1_internet_facing.sql new file mode 100644 index 000000000..fe2dd8b6a --- /dev/null +++ b/policies/queries/elb/elbv1_internet_facing.sql @@ -0,0 +1,11 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Find all Classic ELBs that are Internet Facing' AS title, + account_id, + arn as resource_id, + case when scheme = 'internet-facing' then 'fail' else 'pass' end as status +from + aws_elbv1_load_balancers diff --git a/policies/queries/elb/elbv2_internet_facing.sql b/policies/queries/elb/elbv2_internet_facing.sql new file mode 100644 index 000000000..8f337b37c --- /dev/null +++ b/policies/queries/elb/elbv2_internet_facing.sql @@ -0,0 +1,11 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Find all ELB V2s that are Internet Facing' AS title, + account_id, + arn as resource_id, + case when scheme = 'internet-facing' then 'fail' else 'pass' end as status +from + aws_elbv2_load_balancers diff --git a/policies/queries/elb/elbv2_redirect_http_to_https.sql b/policies/queries/elb/elbv2_redirect_http_to_https.sql new file mode 100644 index 000000000..8a851ed0d --- /dev/null +++ b/policies/queries/elb/elbv2_redirect_http_to_https.sql @@ -0,0 +1,18 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Application Load Balancer should be configured to redirect all HTTP requests to HTTPS' as title, + aws_elbv2_listeners.account_id, + aws_elbv2_listeners.arn as resource_id, + case when + protocol = 'HTTP' and ( + aws_elbv2_listener_default_actions.type != 'REDIRECT' or aws_elbv2_listener_default_actions.redirect_config_protocol != 'HTTPS') + then 'fail' + else 'pass' + end as status +from aws_elbv2_listeners +inner join + aws_elbv2_listener_default_actions on + aws_elbv2_listeners.cq_id = aws_elbv2_listener_default_actions.listener_cq_id diff --git a/policies/queries/emr/emr_cluster_master_nodes_should_not_have_public_ip_addresses.sql b/policies/queries/emr/emr_cluster_master_nodes_should_not_have_public_ip_addresses.sql new file mode 100644 index 000000000..00e6210e8 --- /dev/null +++ b/policies/queries/emr/emr_cluster_master_nodes_should_not_have_public_ip_addresses.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'EMR clusters should not have public ip addresses' as title, + aws_emr_clusters.account_id, + aws_emr_clusters.arn as resource_id, + case when aws_ec2_subnets.map_public_ip_on_launch and aws_emr_clusters.state in ('RUNNING', 'WAITING') then 'fail' + else 'pass' end as status +from + aws_emr_clusters +left outer join aws_ec2_subnets + on aws_emr_clusters.ec2_instance_attribute_subnet_id = aws_ec2_subnets.id diff --git a/policies/queries/guardduty/detector_enabled.sql b/policies/queries/guardduty/detector_enabled.sql new file mode 100644 index 000000000..fb93e479d --- /dev/null +++ b/policies/queries/guardduty/detector_enabled.sql @@ -0,0 +1,35 @@ +insert into aws_policy_results +with enabled_detector_regions as ( + select region + from aws_guardduty_detectors + where status = 'ENABLED' +) + +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'GuardDuty should be enabled' AS title, + r.account_id, + r.region AS resource_id, + case when + enabled = TRUE and e.region is null + then 'fail' else 'pass' end AS status +from aws_regions r +left join enabled_detector_regions e on e.region = r.region +union +-- Add any detector that is enabled but all data sources are disabled +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'GuardDuty should be enabled (detectors)' AS title, + account_id, + region AS resource_id, + case when + data_sources_s3_logs_status != 'ENABLED' and data_sources_cloud_trail_status != 'ENABLED' + and data_sources_dns_logs_status != 'ENABLED' and data_sources_flow_logs_status != 'ENABLED' + then 'fail' else 'pass' end AS status +from aws_guardduty_detectors +where + status = 'ENABLED' diff --git a/policies/queries/iam/avoid_root_usage.sql b/policies/queries/iam/avoid_root_usage.sql new file mode 100644 index 000000000..b9cbb996a --- /dev/null +++ b/policies/queries/iam/avoid_root_usage.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Avoid the use of "root" account. Show used in last 30 days (Scored)' as title, + account_id, + arn as resource_id, + case when + user_name = '' and password_last_used > (now() - '30 days'::INTERVAL) + then 'fail' + else 'pass' + end as status +from aws_iam_users diff --git a/policies/queries/iam/hardware_mfa_enabled_for_root.sql b/policies/queries/iam/hardware_mfa_enabled_for_root.sql new file mode 100644 index 000000000..25ba3a4be --- /dev/null +++ b/policies/queries/iam/hardware_mfa_enabled_for_root.sql @@ -0,0 +1,20 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure hardware MFA is enabled for the "root" account (Scored)' as title, + aws_iam_users.account_id, + arn as resource_id, + case + when aws_iam_users.user_name = '' and ( + serial_number is null or aws_iam_users.mfa_active = FALSE) then 'fail' + when aws_iam_users.user_name = '' and + serial_number is not null and aws_iam_users.mfa_active = FALSE then 'pass' + end as status +from aws_iam_users +left join + aws_iam_virtual_mfa_devices on + aws_iam_virtual_mfa_devices.user_arn = aws_iam_users.arn +where aws_iam_users.user_name = '' +group by aws_iam_users.account_id, aws_iam_users.user_name, serial_number, mfa_active, arn diff --git a/policies/queries/iam/iam_access_keys_rotated_more_than_90_days.sql b/policies/queries/iam/iam_access_keys_rotated_more_than_90_days.sql new file mode 100644 index 000000000..221ef0b78 --- /dev/null +++ b/policies/queries/iam/iam_access_keys_rotated_more_than_90_days.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'IAM users'' access keys should be rotated every 90 days or less' AS title, + account_id, + aws_iam_user_access_keys.access_key_id AS resource_id, + case when date_part('day', now() - last_rotated) > 90 then 'fail' + else 'pass' + end as status +from aws_iam_users + left join + aws_iam_user_access_keys on + aws_iam_users.cq_id = aws_iam_user_access_keys.user_cq_id diff --git a/policies/queries/iam/iam_access_keys_unused_more_than_90_days.sql b/policies/queries/iam/iam_access_keys_unused_more_than_90_days.sql new file mode 100644 index 000000000..cba92ad07 --- /dev/null +++ b/policies/queries/iam/iam_access_keys_unused_more_than_90_days.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Unused IAM user credentials should be removed' AS title, + account_id, + aws_iam_user_access_keys.access_key_id AS resource_id, + case when date_part('day', now() - last_used) > 90 then 'fail' + else 'pass' + end as status +from aws_iam_users + left join + aws_iam_user_access_keys on + aws_iam_users.cq_id = aws_iam_user_access_keys.user_cq_id diff --git a/policies/queries/iam/mfa_enabled_for_console_access.sql b/policies/queries/iam/mfa_enabled_for_console_access.sql new file mode 100644 index 000000000..ea323a2fe --- /dev/null +++ b/policies/queries/iam/mfa_enabled_for_console_access.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure MFA is enabled for all IAM users that have a console password (Scored)' as title, + account_id, + arn as resource_id, + case when + password_enabled and not mfa_active + then 'fail' + else 'pass' + end as status +from aws_iam_users diff --git a/policies/queries/iam/mfa_enabled_for_root.sql b/policies/queries/iam/mfa_enabled_for_root.sql new file mode 100644 index 000000000..d0f6e8c4e --- /dev/null +++ b/policies/queries/iam/mfa_enabled_for_root.sql @@ -0,0 +1,13 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Ensure MFA is enabled for the "root" account' as title, + account_id, + arn as resource_id, + case + when user_name = '' and not mfa_active then 'fail' + when user_name = '' and mfa_active then 'pass' + end as status +from aws_iam_users diff --git a/policies/queries/iam/no_star.sql b/policies/queries/iam/no_star.sql new file mode 100644 index 000000000..63802727e --- /dev/null +++ b/policies/queries/iam/no_star.sql @@ -0,0 +1,40 @@ +insert into aws_policy_results + +with violations as ( + select + policy_cq_id, + COUNT(*) as violations + from aws_iam_policy_versions, + JSONB_ARRAY_ELEMENTS( + case JSONB_TYPEOF(document -> 'Statement') + when 'string' then JSONB_BUILD_ARRAY(document ->> 'Statement') + when 'array' then document -> 'Statement' + end + ) as statement, + JSONB_ARRAY_ELEMENTS_TEXT( + case JSONB_TYPEOF(statement -> 'Resource') + when 'string' then JSONB_BUILD_ARRAY(statement ->> 'Resource') + when 'array' then statement -> 'Resource' end + ) as resource, + JSONB_ARRAY_ELEMENTS_TEXT( case JSONB_TYPEOF(statement -> 'Action') + when 'string' then JSONB_BUILD_ARRAY(statement ->> 'Action') + when 'array' then statement -> 'Action' end + ) as action + where statement ->> 'Effect' = 'Allow' + and resource = '*' + and ( action = '*' or action = '*:*' ) + group by policy_cq_id +) + +select distinct + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'IAM policies should not allow full ''*'' administrative privileges' as title, + account_id, + arn AS resource_id, + case when + violations.policy_cq_id is not null AND violations.violations > 0 + then 'fail' else 'pass' end as status +from aws_iam_policies +left join violations on violations.policy_cq_id = aws_iam_policies.cq_id diff --git a/policies/queries/iam/old_access_keys.sql b/policies/queries/iam/old_access_keys.sql new file mode 100644 index 000000000..edd33d54f --- /dev/null +++ b/policies/queries/iam/old_access_keys.sql @@ -0,0 +1,17 @@ +insert into aws_policy_results +select + :execution_time, + :'framework', + :'check_id', + 'Ensure access keys are rotated every 90 days or less', + account_id, + arn, + case when + last_rotated < (now() - '90 days'::INTERVAL) + then 'fail' + else 'pass' + end +from aws_iam_users +inner join + aws_iam_user_access_keys on + aws_iam_users.cq_id = aws_iam_user_access_keys.user_cq_id diff --git a/policies/queries/iam/password_policy_expire_old_passwords.sql b/policies/queries/iam/password_policy_expire_old_passwords.sql new file mode 100644 index 000000000..c7559bee0 --- /dev/null +++ b/policies/queries/iam/password_policy_expire_old_passwords.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time, + :'framework', + :'check_id', + 'Ensure IAM password policy expires passwords within 90 days or less' as title, + account_id, + account_id, + case when + (max_password_age is null or max_password_age < 90) or policy_exists = false + then 'fail' + else 'pass' + end +from + aws_iam_password_policies diff --git a/policies/queries/iam/password_policy_min_length.sql b/policies/queries/iam/password_policy_min_length.sql new file mode 100644 index 000000000..d8a213a69 --- /dev/null +++ b/policies/queries/iam/password_policy_min_length.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time, + :'framework', + :'check_id', + 'Ensure IAM password policy requires minimum length of 14 or greater', + account_id, + account_id, + case when + (minimum_password_length < 14) or policy_exists = FALSE + then 'fail' + else 'pass' + end +from + aws_iam_password_policies diff --git a/policies/queries/iam/password_policy_min_lowercase.sql b/policies/queries/iam/password_policy_min_lowercase.sql new file mode 100644 index 000000000..adfc6ca5e --- /dev/null +++ b/policies/queries/iam/password_policy_min_lowercase.sql @@ -0,0 +1,16 @@ +insert into aws_policy_results +select + :execution_time, + :'framework', + :'check_id', + 'Ensure IAM password policy requires at least one lowercase letter' as title, + account_id, + account_id, + case when + require_lowercase_characters = false or policy_exists = false + then 'fail' + else 'pass' + end as status +from + aws_iam_password_policies + diff --git a/policies/queries/iam/password_policy_min_number.sql b/policies/queries/iam/password_policy_min_number.sql new file mode 100644 index 000000000..5697b45b6 --- /dev/null +++ b/policies/queries/iam/password_policy_min_number.sql @@ -0,0 +1,16 @@ +insert into aws_policy_results +select + :execution_time, + :'framework', + :'check_id', + 'Ensure IAM password policy requires at least one number', + account_id, + account_id, + case when + require_numbers = FALSE or policy_exists = FALSE + then 'fail' + else 'pass' + end as status +from + aws_iam_password_policies + diff --git a/policies/queries/iam/password_policy_min_one_symbol.sql b/policies/queries/iam/password_policy_min_one_symbol.sql new file mode 100644 index 000000000..73e2809ff --- /dev/null +++ b/policies/queries/iam/password_policy_min_one_symbol.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time, + :'framework', + :'check_id', + 'Ensure IAM password policy requires at least one symbol', + account_id, + account_id, + case when + require_symbols = false or policy_exists = false + then 'fail' + else 'pass' + end as status +from + aws_iam_password_policies diff --git a/policies/queries/iam/password_policy_min_uppercase.sql b/policies/queries/iam/password_policy_min_uppercase.sql new file mode 100644 index 000000000..465a60832 --- /dev/null +++ b/policies/queries/iam/password_policy_min_uppercase.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time, + :'framework', + :'check_id', + 'Ensure IAM password policy requires at least one uppercase letter', + account_id, + account_id, + case when + require_uppercase_characters is not true or policy_exists is not true + then 'fail' + else 'pass' + end +from + aws_iam_password_policies diff --git a/policies/queries/iam/password_policy_prevent_reuse.sql b/policies/queries/iam/password_policy_prevent_reuse.sql new file mode 100644 index 000000000..be984d99b --- /dev/null +++ b/policies/queries/iam/password_policy_prevent_reuse.sql @@ -0,0 +1,16 @@ +insert into aws_policy_results +select + :execution_time, + :'framework', + :'check_id', + 'Ensure IAM password policy prevents password reuse', + account_id, + account_id, + case when + (password_reuse_prevention is null or password_reuse_prevention > 24) + or policy_exists = FALSE + then 'fail' + else 'pass' + end +from + aws_iam_password_policies diff --git a/policies/queries/iam/password_policy_strong.sql b/policies/queries/iam/password_policy_strong.sql new file mode 100644 index 000000000..e8dfd7d1b --- /dev/null +++ b/policies/queries/iam/password_policy_strong.sql @@ -0,0 +1,20 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Password policies for IAM users should have strong configurations' as title, + account_id, + account_id AS resource_id, + case when + ( + require_uppercase_characters is not TRUE + or require_lowercase_characters is not TRUE + or require_numbers is not TRUE + or minimum_password_length < 14 + or password_reuse_prevention is null + or max_password_age is null + or policy_exists is not TRUE + ) + then 'fail' else 'pass' end as status +from aws_iam_password_policies diff --git a/policies/queries/iam/policies_attached_to_groups_roles.sql b/policies/queries/iam/policies_attached_to_groups_roles.sql new file mode 100644 index 000000000..c45c33f3d --- /dev/null +++ b/policies/queries/iam/policies_attached_to_groups_roles.sql @@ -0,0 +1,13 @@ +insert into aws_policy_results +select distinct + :execution_time, + :'framework', + :'check_id', + 'IAM users should not have IAM policies attached', + aws_iam_users.account_id, + arn AS resource_id, + case when + aws_iam_user_attached_policies.user_cq_id is not null + then 'fail' else 'pass' end as status +from aws_iam_users +left join aws_iam_user_attached_policies on aws_iam_users.cq_id = aws_iam_user_attached_policies.user_cq_id diff --git a/policies/queries/iam/policies_with_admin_rights.sql b/policies/queries/iam/policies_with_admin_rights.sql new file mode 100644 index 000000000..0488b8c4d --- /dev/null +++ b/policies/queries/iam/policies_with_admin_rights.sql @@ -0,0 +1,45 @@ +insert into aws_policy_results + +with policy_statements as ( + select + aws_iam_policies.cq_id as cq_id, + JSONB_ARRAY_ELEMENTS( + case JSONB_TYPEOF(aws_iam_policy_versions.document -> 'Statement') + when + 'string' then JSONB_BUILD_ARRAY( + aws_iam_policy_versions.document ->> 'Statement' + ) + when 'array' then aws_iam_policy_versions.document -> 'Statement' end + ) as statement + from + aws_iam_policies + left join aws_iam_policy_versions + on + aws_iam_policies.cq_id = aws_iam_policy_versions.policy_cq_id and aws_iam_policies.default_version_id = aws_iam_policy_versions.version_id + where aws_iam_policies.arn not like 'arn:aws:iam::aws:policy%' +), + +allow_all_statements as ( + select + cq_id, + COUNT(statement) as statements_count + from policy_statements + where (statement ->> 'Action' = '*' + or statement ->> 'Action' like '%"*"%') + and statement ->> 'Effect' = 'Allow' + and (statement ->> 'Resource' = '*' + or statement ->> 'Resource' like '%"*"%') + group by cq_id +) + +select distinct + :execution_time, + :'framework', + :'check_id', + 'IAM policies should not allow full ''*'' administrative privileges' AS title, + aws_iam_policies.account_id, + aws_iam_policies.arn AS resource_id, + CASE WHEN statements_count > 0 THEN 'fail' ELSE 'pass' END AS status +from aws_iam_policies +left join + allow_all_statements on aws_iam_policies.cq_id = allow_all_statements.cq_id diff --git a/policies/queries/iam/root_user_no_access_keys.sql b/policies/queries/iam/root_user_no_access_keys.sql new file mode 100644 index 000000000..b277b4163 --- /dev/null +++ b/policies/queries/iam/root_user_no_access_keys.sql @@ -0,0 +1,17 @@ +insert into aws_policy_results +select + :execution_time, + :'framework', + :'check_id', + 'Ensure no root account access key exists (Scored)', + account_id, + arn, + case when + user_name = '' + then 'fail' + else 'pass' + end +from aws_iam_users +inner join + aws_iam_user_access_keys on + aws_iam_users.cq_id = aws_iam_user_access_keys.user_cq_id diff --git a/policies/queries/iam/unused_creds_disabled.sql b/policies/queries/iam/unused_creds_disabled.sql new file mode 100644 index 000000000..dd32b6182 --- /dev/null +++ b/policies/queries/iam/unused_creds_disabled.sql @@ -0,0 +1,18 @@ +insert into aws_policy_results +select + :execution_time, + :'framework', + :'check_id', + 'Ensure credentials unused for 90 days or greater are disabled (Scored)', + account_id, + arn, + case when + (password_enabled and password_last_used < (now() - '90 days'::INTERVAL) + or (last_used < (now() - '90 days'::INTERVAL))) + then 'fail' + else 'pass' + end +from + aws_iam_users +inner join aws_iam_user_access_keys + on aws_iam_users.cq_id = aws_iam_user_access_keys.user_cq_id diff --git a/policies/queries/iam/wildcard_access_policies.sql b/policies/queries/iam/wildcard_access_policies.sql new file mode 100644 index 000000000..206f00082 --- /dev/null +++ b/policies/queries/iam/wildcard_access_policies.sql @@ -0,0 +1,49 @@ +insert into aws_policy_results + +with policy_statements as ( + select + aws_iam_policies.cq_id as cq_id, + JSONB_ARRAY_ELEMENTS( + case JSONB_TYPEOF(aws_iam_policy_versions.document -> 'Statement') + when + 'string' then JSONB_BUILD_ARRAY( + aws_iam_policy_versions.document ->> 'Statement' + ) + when + 'array' then aws_iam_policy_versions.document -> 'Statement' + end + ) as statement + from + aws_iam_policies + left join aws_iam_policy_versions + on + aws_iam_policies.cq_id = aws_iam_policy_versions.policy_cq_id and aws_iam_policies.default_version_id = aws_iam_policy_versions.version_id + where aws_iam_policies.arn not like 'arn:aws:iam::aws:policy%' +), + +allow_all_statements as ( + select + cq_id, + COUNT(statement) as statements_count + from + policy_statements + where + statement ->> 'Effect' = 'Allow' + and ( + statement ->> 'Action' like '%*%' + or statement ->> 'NotAction' like '%*%') + group by + cq_id +) + +select distinct + :execution_time, + :'framework', + :'check_id', + 'IAM customer managed policies that you create should not allow wildcard actions for services' AS title, + aws_iam_policies.account_id, + aws_iam_policies.arn AS resource_id, + CASE WHEN statements_count > 0 THEN 'fail' ELSE 'pass' END AS status +from aws_iam_policies + left join + allow_all_statements on aws_iam_policies.cq_id = allow_all_statements.cq_id diff --git a/policies/queries/kms/cmk_not_scheduled_for_deletion.sql b/policies/queries/kms/cmk_not_scheduled_for_deletion.sql new file mode 100644 index 000000000..b0c016176 --- /dev/null +++ b/policies/queries/kms/cmk_not_scheduled_for_deletion.sql @@ -0,0 +1,10 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'AWS KMS keys should not be unintentionally deleted' as title, + account_id, + arn as resource_id, + case when key_state = 'PendingDeletion' and manager = 'CUSTOMER' then 'fail' else 'pass' end as status +from aws_kms_keys diff --git a/policies/queries/kms/customer_policy_blocked_kms_actions.sql b/policies/queries/kms/customer_policy_blocked_kms_actions.sql new file mode 100644 index 000000000..b08dcb899 --- /dev/null +++ b/policies/queries/kms/customer_policy_blocked_kms_actions.sql @@ -0,0 +1,44 @@ +insert into aws_policy_results + +with iam_policies as ( + select + document, + account_id, + arn, + aws_iam_policies.cq_id + from aws_iam_policy_versions + inner join + aws_iam_policies on + aws_iam_policies.cq_id = aws_iam_policy_versions.policy_cq_id +), + +violations as ( + select distinct cq_id + from iam_policies, + jsonb_array_elements( + case jsonb_typeof(document -> 'Statement') + when 'string' then jsonb_build_array(document ->> 'Statement') + when 'array' then document -> 'Statement' + end + ) as statement + where + not( + arn like 'arn:aws:iam::aws:policy%' or arn like 'arn:aws-us-gov:iam::aws:policy%' + ) + and statement ->> 'Effect' = 'Allow' + AND statement -> 'Resource'?| array['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*'] -- noqa + AND statement -> 'Action' ?| array['*', 'kms:*', 'kms:decrypt', 'kms:reencryptfrom', 'kms:reencrypt*'] -- noqa +) + +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'IAM customer managed policies should not allow decryption and re-encryption actions on all KMS keys' AS title, + account_id, + arn AS resource_id, + case when + violations.cq_id is not null + then 'fail' else 'pass' end as status +from aws_iam_policies +left join violations on violations.cq_id = aws_iam_policies.cq_id diff --git a/policies/queries/kms/inline_policy_blocked_kms_actions.sql b/policies/queries/kms/inline_policy_blocked_kms_actions.sql new file mode 100644 index 000000000..f84c7b6b0 --- /dev/null +++ b/policies/queries/kms/inline_policy_blocked_kms_actions.sql @@ -0,0 +1,86 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'IAM principals should not have IAM inline policies that allow decryption and re-encryption actions on all KMS keys' AS title, + account_id, + arn AS resource_id, + 'fail' AS status -- TODO FIXME +from + ( + -- select all user policies + select + statement, + aws_iam_users.account_id, + arn, + policy_name, + aws_iam_users.cq_id + from aws_iam_user_policies + cross join lateral jsonb_array_elements( + case jsonb_typeof(policy_document -> 'Statement') + when + 'string' then jsonb_build_array( + policy_document ->> 'Statement' + ) + when 'array' then policy_document -> 'Statement' end + ) as statement + inner join + aws_iam_users on + aws_iam_users.cq_id = aws_iam_user_policies.user_cq_id + union + -- select all role policies + select + statement, + aws_iam_roles.account_id, + arn, + policy_name, + aws_iam_roles.cq_id + from aws_iam_role_policies + cross join lateral jsonb_array_elements( + case jsonb_typeof(policy_document -> 'Statement') + when + 'string' then jsonb_build_array( + policy_document ->> 'Statement' + ) + when 'array' then policy_document -> 'Statement' end + ) as statement + inner join + aws_iam_roles on + aws_iam_roles.cq_id = aws_iam_role_policies.role_cq_id + where lower(arn) not like 'arn:aws:iam::%:role/aws-service-role/%' + union + -- select all group policies + select + statement, + aws_iam_groups.account_id, + arn, + policy_name, + aws_iam_groups.cq_id + from aws_iam_group_policies + cross join lateral jsonb_array_elements( + case jsonb_typeof(policy_document -> 'Statement') + when + 'string' then jsonb_build_array( + policy_document ->> 'Statement' + ) + when 'array' then policy_document -> 'Statement' end + ) as statement + inner join aws_iam_groups on aws_iam_groups.cq_id = aws_iam_group_policies.group_cq_id) as t +where + statement ->> 'Effect' = 'Allow' + and lower(statement::TEXT)::JSONB -> 'resource' ?| array[ + '*', + 'arn:aws:kms:*:*:key/*', + 'arn:aws:kms:*:' || account_id || ':key/*' + 'arn:aws:kms:*:*:alias/*', + 'arn:aws:kms:*:' || account_id || ':alias/*' + ] + + and lower(statement::TEXT)::JSONB -> 'action' ?| array[ + '*', + 'kms:*', + 'kms:decrypt', + 'kms:encrypt*', + 'kms:reencryptfrom' + ] diff --git a/policies/queries/kms/rotation_enabled_for_customer_key.sql b/policies/queries/kms/rotation_enabled_for_customer_key.sql new file mode 100644 index 000000000..83a22d363 --- /dev/null +++ b/policies/queries/kms/rotation_enabled_for_customer_key.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time, + :'framework', + :'check_id', + 'Ensure rotation for customer created CMKs is enabled (Scored)', + account_id, + arn, + case when + rotation_enabled is FALSE and manager = 'CUSTOMER' + then 'fail' + else 'pass' + end +from aws_kms_keys diff --git a/policies/queries/lambda/functions_with_public_egress.sql b/policies/queries/lambda/functions_with_public_egress.sql new file mode 100644 index 000000000..35e5f17d2 --- /dev/null +++ b/policies/queries/lambda/functions_with_public_egress.sql @@ -0,0 +1,47 @@ +insert into aws_policy_results +select distinct + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Find all ec2 instances that have unrestricted access to the internet' AS title, + account_id, + arn AS resource_id, + 'fail' AS status -- TODO FIXME +from aws_lambda_functions, + UNNEST(vpc_config_security_group_ids) as sgs, + UNNEST(vpc_config_subnet_ids) as sns +where sns in + -- Find all subnets that include a route table that inclues a catchall route + (select subnet_id + from public.aws_ec2_route_tables + inner join + aws_ec2_route_table_associations on + aws_ec2_route_table_associations.route_table_cq_id = aws_ec2_route_tables.cq_id + where aws_ec2_route_tables.cq_id in + -- Find all routes in any route table that contains a route to 0.0.0.0/0 or ::/0 + (select route_table_cq_id + from public.aws_ec2_route_table_routes + where destination_cidr_block = '0.0.0.0/0' + or destination_ipv6_cidr_block = '::/0')) + and sgs in + -- Find all functions that have egress rule that allows access to all ip addresses + (select group_id + from aws_ec2_instance_security_groups + inner join view_aws_security_group_egress_rules on group_id = id + where (ip = '0.0.0.0/0' + or ip = '::/0') ) +union +-- Find all Lambda functions that do not run in a VPC +select distinct + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Find all ec2 instances that have unrestricted access to the internet' AS title, + account_id, + arn AS resource_id, + 'fail' AS status -- TODO FIXME +from aws_lambda_functions +where vpc_config_vpc_id is null + or vpc_config_vpc_id = '' + +-- Note: We do not restrict the search to specific Runtimes diff --git a/policies/queries/lambda/lambda_function_in_vpc.sql b/policies/queries/lambda/lambda_function_in_vpc.sql new file mode 100644 index 000000000..a45c899a6 --- /dev/null +++ b/policies/queries/lambda/lambda_function_in_vpc.sql @@ -0,0 +1,10 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'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 vpc_config_vpc_id is null or vpc_config_vpc_id = '' then 'fail' else 'pass' end as status +from aws_lambda_functions diff --git a/policies/queries/lambda/lambda_function_prohibit_public_access.sql b/policies/queries/lambda/lambda_function_prohibit_public_access.sql new file mode 100644 index 000000000..4f7e97c23 --- /dev/null +++ b/policies/queries/lambda/lambda_function_prohibit_public_access.sql @@ -0,0 +1,23 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Lambda functions should prohibit public access' as title, + account_id, + arn as resource_id, + 'fail' as status -- TODO FIXME +from aws_lambda_functions, + jsonb_array_elements( + case jsonb_typeof(policy_document -> 'Statement') + when + 'string' then jsonb_build_array(policy_document ->> 'Statement') + when 'array' then policy_document -> 'Statement' + end + ) as statement +where statement ->> 'Effect' = 'Allow' + and ( + statement ->> 'Principal' = '*' + or statement -> 'Principal' ->> 'AWS' = '*' + or (statement -> 'Principal' ->> 'AWS')::JSONB ? '*' + ) diff --git a/policies/queries/lambda/lambda_functions_should_use_supported_runtimes.sql b/policies/queries/lambda/lambda_functions_should_use_supported_runtimes.sql new file mode 100644 index 000000000..23be4d906 --- /dev/null +++ b/policies/queries/lambda/lambda_functions_should_use_supported_runtimes.sql @@ -0,0 +1,13 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Lambda functions should use supported runtimes' as title, + account_id, + arn AS resource_id, + case when r.name is null then 'fail' + else 'pass' end AS status +from aws_lambda_functions f +left join aws_lambda_runtimes r on r.name=f.runtime +where package_type != 'Image' diff --git a/policies/queries/rds/amazon_aurora_clusters_should_have_backtracking_enabled.sql b/policies/queries/rds/amazon_aurora_clusters_should_have_backtracking_enabled.sql new file mode 100644 index 000000000..7e85d75f8 --- /dev/null +++ b/policies/queries/rds/amazon_aurora_clusters_should_have_backtracking_enabled.sql @@ -0,0 +1,12 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Amazon Aurora clusters should have backtracking enabled' as title, + account_id, + arn AS resource_id, + case when backtrack_window is null then 'fail' else 'pass' end as status +from aws_rds_clusters +where + engine in ('aurora', 'aurora-mysql', 'mysql') diff --git a/policies/queries/rds/database_logging_should_be_enabled.sql b/policies/queries/rds/database_logging_should_be_enabled.sql new file mode 100644 index 000000000..513a3cc55 --- /dev/null +++ b/policies/queries/rds/database_logging_should_be_enabled.sql @@ -0,0 +1,22 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Database logging should be enabled' as title, + account_id, + arn AS resource_id, + case when + enabled_cloudwatch_logs_exports is null + or (engine in ('aurora', 'aurora-mysql', 'mariadb', 'mysql') + and not enabled_cloudwatch_logs_exports @> '{audit,error,general,slowquery}' + ) + or (engine like '%postgres%' + and not enabled_cloudwatch_logs_exports @> '{postgresql,upgrade}') + or (engine like '%oracle%' + and not enabled_cloudwatch_logs_exports @> '{alert,audit,trace,listener}' + ) + or (engine like '%sqlserver%' + and not enabled_cloudwatch_logs_exports @> '{error,agent}') + then 'fail' else 'pass' end as status +from aws_rds_instances diff --git a/policies/queries/rds/enhanced_monitoring_should_be_configured_for_rds_db_instances_and_clusters.sql b/policies/queries/rds/enhanced_monitoring_should_be_configured_for_rds_db_instances_and_clusters.sql new file mode 100644 index 000000000..5e9a68989 --- /dev/null +++ b/policies/queries/rds/enhanced_monitoring_should_be_configured_for_rds_db_instances_and_clusters.sql @@ -0,0 +1,10 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'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 diff --git a/policies/queries/rds/iam_authentication_should_be_configured_for_rds_clusters.sql b/policies/queries/rds/iam_authentication_should_be_configured_for_rds_clusters.sql new file mode 100644 index 000000000..c9fbde106 --- /dev/null +++ b/policies/queries/rds/iam_authentication_should_be_configured_for_rds_clusters.sql @@ -0,0 +1,10 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'IAM authentication should be configured for RDS clusters' as title, + account_id, + arn AS resource_id, + case when iam_database_authentication_enabled is not TRUE then 'fail' else 'pass' end as status +from aws_rds_clusters diff --git a/policies/queries/rds/iam_authentication_should_be_configured_for_rds_instances.sql b/policies/queries/rds/iam_authentication_should_be_configured_for_rds_instances.sql new file mode 100644 index 000000000..791c32664 --- /dev/null +++ b/policies/queries/rds/iam_authentication_should_be_configured_for_rds_instances.sql @@ -0,0 +1,10 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'IAM authentication should be configured for RDS instances' as title, + account_id, + arn AS resource_id, + case when iam_database_authentication_enabled is not TRUE then 'fail' else 'pass' end as status +from aws_rds_instances diff --git a/policies/queries/rds/rds_automatic_minor_version_upgrades_should_be_enabled.sql b/policies/queries/rds/rds_automatic_minor_version_upgrades_should_be_enabled.sql new file mode 100644 index 000000000..8a2971c92 --- /dev/null +++ b/policies/queries/rds/rds_automatic_minor_version_upgrades_should_be_enabled.sql @@ -0,0 +1,10 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'RDS automatic minor version upgrades should be enabled' as title, + account_id, + arn AS resource_id, + case when auto_minor_version_upgrade is not TRUE then 'fail' else 'pass' end as status +from aws_rds_instances diff --git a/policies/queries/rds/rds_cluster_snapshots_and_database_snapshots_should_be_encrypted_at_rest.sql b/policies/queries/rds/rds_cluster_snapshots_and_database_snapshots_should_be_encrypted_at_rest.sql new file mode 100644 index 000000000..4a4e5e057 --- /dev/null +++ b/policies/queries/rds/rds_cluster_snapshots_and_database_snapshots_should_be_encrypted_at_rest.sql @@ -0,0 +1,24 @@ +insert into aws_policy_results +( +select + :execution_time as execution_time, + :'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 is not TRUE then 'fail' else 'pass' end as status +from aws_rds_cluster_snapshots +) +union +( + select + :execution_time as execution_time, + :'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 is not TRUE then 'fail' else 'pass' end as status + from aws_rds_db_snapshots +) diff --git a/policies/queries/rds/rds_clusters_should_have_deletion_protection_enabled.sql b/policies/queries/rds/rds_clusters_should_have_deletion_protection_enabled.sql new file mode 100644 index 000000000..37947329c --- /dev/null +++ b/policies/queries/rds/rds_clusters_should_have_deletion_protection_enabled.sql @@ -0,0 +1,10 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'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 is not TRUE then 'fail' else 'pass' end as status +from aws_rds_clusters diff --git a/policies/queries/rds/rds_databases_and_clusters_should_not_use_a_database_engine_default_port.sql b/policies/queries/rds/rds_databases_and_clusters_should_not_use_a_database_engine_default_port.sql new file mode 100644 index 000000000..ba02aebec --- /dev/null +++ b/policies/queries/rds/rds_databases_and_clusters_should_not_use_a_database_engine_default_port.sql @@ -0,0 +1,34 @@ +insert into aws_policy_results +( + select + :execution_time as execution_time, + :'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 +( + select + :execution_time as execution_time, + :'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 instance_port = 3306 + ) + or (engine like '%postgres%' and instance_port = '5432') + or (engine like '%oracle%' and instance_port = '1521') + or (engine like '%sqlserver%' and instance_port = '1433') + then 'fail' else 'pass' end as status + from aws_rds_instances +) diff --git a/policies/queries/rds/rds_db_clusters_should_be_configured_for_multiple_availability_zones.sql b/policies/queries/rds/rds_db_clusters_should_be_configured_for_multiple_availability_zones.sql new file mode 100644 index 000000000..91fb6d1c6 --- /dev/null +++ b/policies/queries/rds/rds_db_clusters_should_be_configured_for_multiple_availability_zones.sql @@ -0,0 +1,10 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'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 is not TRUE then 'fail' else 'pass' end as status +from aws_rds_clusters diff --git a/policies/queries/rds/rds_db_clusters_should_be_configured_to_copy_tags_to_snapshots.sql b/policies/queries/rds/rds_db_clusters_should_be_configured_to_copy_tags_to_snapshots.sql new file mode 100644 index 000000000..7c3e79e67 --- /dev/null +++ b/policies/queries/rds/rds_db_clusters_should_be_configured_to_copy_tags_to_snapshots.sql @@ -0,0 +1,10 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'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 is not TRUE then 'fail' else 'pass' end as status +from aws_rds_clusters diff --git a/policies/queries/rds/rds_db_instances_should_be_configured_to_copy_tags_to_snapshots.sql b/policies/queries/rds/rds_db_instances_should_be_configured_to_copy_tags_to_snapshots.sql new file mode 100644 index 000000000..d6b105bd8 --- /dev/null +++ b/policies/queries/rds/rds_db_instances_should_be_configured_to_copy_tags_to_snapshots.sql @@ -0,0 +1,10 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'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 is not TRUE then 'fail' else 'pass' end as status +from aws_rds_instances diff --git a/policies/queries/rds/rds_db_instances_should_be_configured_with_multiple_availability_zones.sql b/policies/queries/rds/rds_db_instances_should_be_configured_with_multiple_availability_zones.sql new file mode 100644 index 000000000..71771d83d --- /dev/null +++ b/policies/queries/rds/rds_db_instances_should_be_configured_with_multiple_availability_zones.sql @@ -0,0 +1,10 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'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 is not TRUE then 'fail' else 'pass' end as status +from aws_rds_instances diff --git a/policies/queries/rds/rds_db_instances_should_have_deletion_protection_enabled.sql b/policies/queries/rds/rds_db_instances_should_have_deletion_protection_enabled.sql new file mode 100644 index 000000000..bda27b269 --- /dev/null +++ b/policies/queries/rds/rds_db_instances_should_have_deletion_protection_enabled.sql @@ -0,0 +1,10 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'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 is not TRUE then 'fail' else 'pass' end as status +from aws_rds_instances diff --git a/policies/queries/rds/rds_db_instances_should_have_encryption_at_rest_enabled.sql b/policies/queries/rds/rds_db_instances_should_have_encryption_at_rest_enabled.sql new file mode 100644 index 000000000..ecc483028 --- /dev/null +++ b/policies/queries/rds/rds_db_instances_should_have_encryption_at_rest_enabled.sql @@ -0,0 +1,10 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'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 is not TRUE then 'fail' else 'pass' end as status +from aws_rds_instances diff --git a/policies/queries/rds/rds_db_instances_should_prohibit_public_access.sql b/policies/queries/rds/rds_db_instances_should_prohibit_public_access.sql new file mode 100644 index 000000000..fa84963c7 --- /dev/null +++ b/policies/queries/rds/rds_db_instances_should_prohibit_public_access.sql @@ -0,0 +1,10 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'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 is not TRUE then 'fail' else 'pass' end as status +from aws_rds_instances diff --git a/policies/queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_cluster_events.sql b/policies/queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_cluster_events.sql new file mode 100644 index 000000000..3ef1d1025 --- /dev/null +++ b/policies/queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_cluster_events.sql @@ -0,0 +1,53 @@ +insert into aws_policy_results + +with any_category as ( + select distinct TRUE as any_category + from aws_rds_event_subscriptions + where + (source_type is null or source_type = 'db-cluster') + and event_categories_list is null +), + +any_source_id as ( + select COALESCE(ARRAY_AGG(category), '{}'::TEXT[]) as any_source_categories + from + aws_rds_event_subscriptions, + UNNEST(event_categories_list) as category + where + source_type = 'db-cluster' + and event_categories_list is not null +), + +specific_categories as ( + select + source_id, + ARRAY_AGG(category) as specific_cats + from + aws_rds_event_subscriptions, + UNNEST(source_ids_list) as source_id, + UNNEST(event_categories_list) as category + where source_type = 'db-cluster' + group by source_id +) + +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'An RDS event notifications subscription should be configured for critical cluster events' as title, + account_id, + arn as resource_id, + case when + any_category is not TRUE + and not any_source_categories @> '{"failure","maintenance"}' + and ( + specific_cats is null or not specific_cats @> '{"failure","maintenance"}' + ) + then 'fail' else 'pass' end as status +from + aws_rds_clusters +left outer join any_category on TRUE +inner join any_source_id on TRUE +left outer join + specific_categories on + db_cluster_identifier = specific_categories.source_id diff --git a/policies/queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_database_instance_events.sql b/policies/queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_database_instance_events.sql new file mode 100644 index 000000000..54969fc6f --- /dev/null +++ b/policies/queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_database_instance_events.sql @@ -0,0 +1,52 @@ +insert into aws_policy_results + +with any_category as ( + select distinct TRUE as any_category + from aws_rds_event_subscriptions + where + (source_type is null or source_type = 'db-instance') + and event_categories_list is null +), + +any_source_id as ( + select COALESCE(ARRAY_AGG(category), '{}'::TEXT[]) as any_source_categories + from + aws_rds_event_subscriptions, + UNNEST(event_categories_list) as category + where + source_type = 'db-instance' + and event_categories_list is not null +), + +specific_categories as ( + select + source_id, + ARRAY_AGG(category) as specific_cats + from + aws_rds_event_subscriptions, + UNNEST(source_ids_list) as source_id, + UNNEST(event_categories_list) as category + where source_type = 'db-instance' + group by source_id +) + +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'An RDS event notifications subscription should be configured for critical database instance events' as title, + aws_rds_instances.account_id, + aws_rds_instances.arn as resource_id, + case when + any_category is not TRUE + and not any_source_categories @> '{"maintenance","configuration change","failure"}' + and ( + specific_cats is null or not specific_cats @> '{"maintenance","configuration change","failure"}' + ) + then 'fail' else 'pass' end as status +from + aws_rds_instances +left outer join any_category on TRUE +inner join any_source_id on TRUE +left outer join + specific_categories on user_instance_id = specific_categories.source_id diff --git a/policies/queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_database_parameter_group_events.sql b/policies/queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_database_parameter_group_events.sql new file mode 100644 index 000000000..7d6f0a16b --- /dev/null +++ b/policies/queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_database_parameter_group_events.sql @@ -0,0 +1,53 @@ +insert into aws_policy_results + +with any_category as ( + select distinct TRUE as any_category + from aws_rds_event_subscriptions + where + (source_type is null or source_type = 'db-parameter-group') + and event_categories_list is null +), + +any_source_id as ( + select COALESCE(ARRAY_AGG(category), '{}'::TEXT[]) as any_source_categories + from + aws_rds_event_subscriptions, + UNNEST(event_categories_list) as category + where + source_type = 'db-parameter-group' + and event_categories_list is not null +), + +specific_categories as ( + select + source_id, + ARRAY_AGG(category) as specific_cats + from + aws_rds_event_subscriptions, + UNNEST(source_ids_list) as source_id, + UNNEST(event_categories_list) as category + where source_type = 'db-parameter-group' + group by source_id +) + +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'An RDS event notifications subscription should be configured for critical database parameter group events' as title, + aws_rds_db_parameter_groups.account_id, + aws_rds_db_parameter_groups.arn as resource_id, + case when + any_category is not TRUE + and not any_source_categories @> '{"configuration change"}' + and ( + specific_cats is null or not specific_cats @> '{"configuration change"}' + ) + then 'fail' else 'pass' end as status +from + aws_rds_db_parameter_groups +left outer join any_category on TRUE +inner join any_source_id on TRUE +left outer join + specific_categories on + aws_rds_db_parameter_groups.name = specific_categories.source_id diff --git a/policies/queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_database_security_group_events.sql b/policies/queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_database_security_group_events.sql new file mode 100644 index 000000000..cab828115 --- /dev/null +++ b/policies/queries/rds/rds_event_notifications_subscription_should_be_configured_for_critical_database_security_group_events.sql @@ -0,0 +1,53 @@ +insert into aws_policy_results + +with any_category as ( + select distinct TRUE as any_category + from aws_rds_event_subscriptions + where + (source_type is null or source_type = 'db-security-group') + and event_categories_list is null +), + +any_source_id as ( + select COALESCE(ARRAY_AGG(category), '{}'::TEXT[]) as any_source_categories + from + aws_rds_event_subscriptions, + UNNEST(event_categories_list) as category + where + source_type = 'db-security-group' + and event_categories_list is not null +), + +specific_categories as ( + select + source_id, + ARRAY_AGG(category) as specific_cats + from + aws_rds_event_subscriptions, + UNNEST(source_ids_list) as source_id, + UNNEST(event_categories_list) as category + where source_type = 'db-security-group' + group by source_id +) + +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'An RDS event notifications subscription should be configured for critical database security group events' as title, + aws_rds_db_security_groups.account_id, + aws_rds_db_security_groups.arn as resource_id, + case when + any_category is not TRUE + and not any_source_categories @> '{"configuration change","failure"}' + and ( + specific_cats is null or not specific_cats @> '{"configuration change","failure"}' + ) + then 'fail' else 'pass' end as status +from + aws_rds_db_security_groups +left outer join any_category on TRUE +inner join any_source_id on TRUE +left outer join + specific_categories on + aws_rds_db_security_groups.name = specific_categories.source_id diff --git a/policies/queries/rds/rds_instances_should_be_deployed_in_a_vpc.sql b/policies/queries/rds/rds_instances_should_be_deployed_in_a_vpc.sql new file mode 100644 index 000000000..26ef25a49 --- /dev/null +++ b/policies/queries/rds/rds_instances_should_be_deployed_in_a_vpc.sql @@ -0,0 +1,10 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'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 subnet_group_vpc_id is null then 'fail' else 'pass' end as status +from aws_rds_instances diff --git a/policies/queries/rds/snapshots_should_prohibit_public_access.sql b/policies/queries/rds/snapshots_should_prohibit_public_access.sql new file mode 100644 index 000000000..428cb2b6e --- /dev/null +++ b/policies/queries/rds/snapshots_should_prohibit_public_access.sql @@ -0,0 +1,13 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'RDS snapshots should be private' as title, + account_id, + arn AS resource_id, + case when + (attrs ->> 'AttributeName' is not distinct from 'restore') + and (attrs -> 'AttributeValues') ? 'all' + then 'fail' else 'pass' end as status +from aws_rds_cluster_snapshots, jsonb_array_elements(attributes) as attrs diff --git a/policies/queries/redshift/cluster_publicly_accessible.sql b/policies/queries/redshift/cluster_publicly_accessible.sql new file mode 100644 index 000000000..476d63bde --- /dev/null +++ b/policies/queries/redshift/cluster_publicly_accessible.sql @@ -0,0 +1,10 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Amazon Redshift clusters should prohibit public access' as title, + account_id, + arn AS resource_id, + case when publicly_accessible is TRUE then 'fail' else 'pass' end as status +from aws_redshift_clusters diff --git a/policies/queries/redshift/clusters_should_be_encrypted_in_transit.sql b/policies/queries/redshift/clusters_should_be_encrypted_in_transit.sql new file mode 100644 index 000000000..f64615254 --- /dev/null +++ b/policies/queries/redshift/clusters_should_be_encrypted_in_transit.sql @@ -0,0 +1,28 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Connections to Amazon Redshift clusters should be encrypted in transit' as title, + account_id, + arn as resource_id, + 'fail' as status -- TODO FIXME +from aws_redshift_clusters as rsc + +where exists(select 1 + from aws_redshift_cluster_parameter_groups as rscpg + inner join aws_redshift_cluster_parameters as rscp + on + rscpg.cq_id = rscp.cluster_parameter_group_cq_id + where rsc.cq_id = rscpg.cluster_cq_id + and ( + rscp.parameter_name = 'require_ssl' and rscp.parameter_value = 'false' + ) + or ( + rscp.parameter_name = 'require_ssl' and rscp.parameter_value is null + ) + or not exists((select 1 + from aws_redshift_cluster_parameters + where cluster_parameter_group_cq_id = rscpg.cq_id + and parameter_name = 'require_ssl')) +) diff --git a/policies/queries/redshift/clusters_should_have_audit_logging_enabled.sql b/policies/queries/redshift/clusters_should_have_audit_logging_enabled.sql new file mode 100644 index 000000000..00b7c361c --- /dev/null +++ b/policies/queries/redshift/clusters_should_have_audit_logging_enabled.sql @@ -0,0 +1,16 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Amazon Redshift clusters should have audit logging enabled' as title, + account_id, + arn as resource_id, + case when + jsonb_typeof(logging_status -> 'LoggingEnabled') is null + or ( + jsonb_typeof(logging_status -> 'LoggingEnabled') is not null + and (logging_status ->> 'LoggingEnabled')::BOOLEAN is FALSE + ) + then 'fail' else 'pass' end as status +from aws_redshift_clusters diff --git a/policies/queries/redshift/clusters_should_have_automatic_snapshots_enabled.sql b/policies/queries/redshift/clusters_should_have_automatic_snapshots_enabled.sql new file mode 100644 index 000000000..c83f33cde --- /dev/null +++ b/policies/queries/redshift/clusters_should_have_automatic_snapshots_enabled.sql @@ -0,0 +1,12 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Amazon Redshift clusters should have automatic snapshots enabled' as title, + account_id, + arn as resource_id, + case when + automated_snapshot_retention_period < 7 or automated_snapshot_retention_period is null + then 'fail' else 'pass' end as status +from aws_redshift_clusters diff --git a/policies/queries/redshift/clusters_should_have_automatic_upgrades_to_major_versions_enabled.sql b/policies/queries/redshift/clusters_should_have_automatic_upgrades_to_major_versions_enabled.sql new file mode 100644 index 000000000..1fe0bbc0f --- /dev/null +++ b/policies/queries/redshift/clusters_should_have_automatic_upgrades_to_major_versions_enabled.sql @@ -0,0 +1,12 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Amazon Redshift should have automatic upgrades to major versions enabled' as title, + account_id, + arn as resource_id, + case when + allow_version_upgrade is FALSE or allow_version_upgrade is null + then 'fail' else 'pass' end as status +from aws_redshift_clusters diff --git a/policies/queries/redshift/clusters_should_use_enhanced_vpc_routing.sql b/policies/queries/redshift/clusters_should_use_enhanced_vpc_routing.sql new file mode 100644 index 000000000..1985d12cb --- /dev/null +++ b/policies/queries/redshift/clusters_should_use_enhanced_vpc_routing.sql @@ -0,0 +1,12 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Amazon Redshift clusters should use enhanced VPC routing' as title, + account_id, + arn as resource_id, + case when + enhanced_vpc_routing is FALSE or enhanced_vpc_routing is null + then 'fail' else 'pass' end as status +from aws_redshift_clusters diff --git a/policies/queries/s3/account_level_public_access_blocks.sql b/policies/queries/s3/account_level_public_access_blocks.sql new file mode 100644 index 000000000..741cbbb6e --- /dev/null +++ b/policies/queries/s3/account_level_public_access_blocks.sql @@ -0,0 +1,20 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'S3 Block Public Access setting should be enabled' as title, + aws_accounts.account_id, + aws_accounts.account_id AS resource_id, + case when + config_exists is not TRUE + or block_public_acls is not TRUE + or block_public_policy is not TRUE + or ignore_public_acls is not TRUE + or restrict_public_buckets is not TRUE + then 'fail' else 'pass' end as status +from + aws_accounts +left join + aws_s3_account_config on + aws_accounts.account_id = aws_s3_account_config.account_id diff --git a/policies/queries/s3/bucket_level_public_access_blocks.sql b/policies/queries/s3/bucket_level_public_access_blocks.sql new file mode 100644 index 000000000..2c0fd0e1e --- /dev/null +++ b/policies/queries/s3/bucket_level_public_access_blocks.sql @@ -0,0 +1,16 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'S3 Block Public Access (bucket) setting should be enabled' as title, + account_id, + arn AS resource_id, + case when + block_public_acls is not TRUE + or block_public_policy is not TRUE + or ignore_public_acls is not TRUE + or restrict_public_buckets is not TRUE + then 'fail' else 'pass' end as status +from + aws_s3_buckets diff --git a/policies/queries/s3/deny_http_requests.sql b/policies/queries/s3/deny_http_requests.sql new file mode 100644 index 000000000..98a10f9d8 --- /dev/null +++ b/policies/queries/s3/deny_http_requests.sql @@ -0,0 +1,42 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + '' as title, -- TODO FIXME + account_id, + arn as resource_id, + 'fail' as status -- TODO FIXME +from + aws_s3_buckets +where + arn not in ( + -- Find all buckets that have a bucket policy that denies non SSL requests + select arn + from (select aws_s3_buckets.arn, + statements, + statements -> 'Principal' as principals + from aws_s3_buckets, + jsonb_array_elements( + case jsonb_typeof(policy -> 'Statement') + when + 'string' then jsonb_build_array( + policy ->> 'Statement' + ) + when 'array' then policy -> 'Statement' + end + ) as statements + where statements -> 'Effect' = '"Deny"') as foo, + jsonb_array_elements_text( + statements -> 'Condition' -> 'Bool' -> 'aws:securetransport' + ) as ssl + where principals = '"*"' + or ( + principals::JSONB ? 'AWS' + and ( + principals -> 'AWS' = '"*"' + or principals -> 'AWS' @> '"*"' + ) + ) + and ssl::BOOL = FALSE + ) diff --git a/policies/queries/s3/publicly_readable_buckets.sql b/policies/queries/s3/publicly_readable_buckets.sql new file mode 100644 index 000000000..4b0cd830f --- /dev/null +++ b/policies/queries/s3/publicly_readable_buckets.sql @@ -0,0 +1,72 @@ +insert into aws_policy_results +with policy_allow_public as ( + select + arn, + bucket_cq_id, + count(*) as statement_count + from + ( + select + aws_s3_buckets.arn, + aws_s3_buckets.cq_id as bucket_cq_id, + statements -> 'Principal' as principals + from + aws_s3_buckets, + jsonb_array_elements( + case jsonb_typeof(policy -> 'Statement') + when + 'string' then jsonb_build_array( + policy ->> 'Statement' + ) + when 'array' then policy -> 'Statement' + end + ) as statements + where + statements -> 'Effect' = '"Allow"' + ) as foo + where + principals = '"*"' + or ( + principals::JSONB ? 'AWS' + and ( + principals -> 'AWS' = '"*"' + or principals -> 'AWS' @> '"*"' + ) + ) + group by + arn, bucket_cq_id +) + +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'S3 buckets should prohibit public read access' as title, + aws_s3_buckets.account_id, + aws_s3_buckets.arn as resource_id, + 'fail' as status -- TODO FIXME +from + -- Find and join all bucket ACLS that givea public write access + aws_s3_buckets +left join + aws_s3_bucket_grants on + aws_s3_buckets.cq_id = aws_s3_bucket_grants.bucket_cq_id +-- Find all statements that could give public allow access +-- Statements that give public access have 1) Effect == Allow 2) One of the following principal: +-- Principal = {"AWS": "*"} +-- Principal = {"AWS": ["arn:aws:iam::12345678910:root", "*"]} +-- Principal = "*" +left join policy_allow_public on + aws_s3_buckets.cq_id = policy_allow_public.bucket_cq_id +where + ( + aws_s3_buckets.block_public_acls != TRUE + and ( + uri = 'http://acs.amazonaws.com/groups/global/AllUsers' + and permission in ('READ_ACP', 'FULL_CONTROL') + ) + ) + or ( + aws_s3_buckets.block_public_policy != TRUE + and policy_allow_public.statement_count > 0 + ) diff --git a/policies/queries/s3/publicly_writable_buckets.sql b/policies/queries/s3/publicly_writable_buckets.sql new file mode 100644 index 000000000..0c1ca41b0 --- /dev/null +++ b/policies/queries/s3/publicly_writable_buckets.sql @@ -0,0 +1,72 @@ +insert into aws_policy_results +with policy_allow_public as ( + select + arn, + bucket_cq_id, + count(*) as statement_count + from + ( + select + aws_s3_buckets.arn, + aws_s3_buckets.cq_id as bucket_cq_id, + statements -> 'Principal' as principals + from + aws_s3_buckets, + jsonb_array_elements( + case jsonb_typeof(policy -> 'Statement') + when + 'string' then jsonb_build_array( + policy ->> 'Statement' + ) + when 'array' then policy -> 'Statement' + end + ) as statements + where + statements -> 'Effect' = '"Allow"' + ) as foo + where + principals = '"*"' + or ( + principals::JSONB ? 'AWS' + and ( + principals -> 'AWS' = '"*"' + or principals -> 'AWS' @> '"*"' + ) + ) + group by + arn, bucket_cq_id +) + +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'S3 buckets should prohibit public write access' as title, + aws_s3_buckets.account_id, + aws_s3_buckets.arn as resource_id, + 'fail' as status -- TODO FIXME +from + -- Find and join all bucket ACLS that give a public write access + aws_s3_buckets +left join + aws_s3_bucket_grants on + aws_s3_buckets.cq_id = aws_s3_bucket_grants.bucket_cq_id +-- Find all statements that could give public allow access +-- Statements that give public access have 1) Effect == Allow 2) One of the following principal: +-- Principal = {"AWS": "*"} +-- Principal = {"AWS": ["arn:aws:iam::12345678910:root", "*"]} +-- Principal = "*" +left join policy_allow_public on + aws_s3_buckets.cq_id = policy_allow_public.bucket_cq_id +where + ( + aws_s3_buckets.block_public_acls != TRUE + and ( + uri = 'http://acs.amazonaws.com/groups/global/AllUsers' + and permission in ('WRITE_ACP', 'FULL_CONTROL') + ) + ) + or ( + aws_s3_buckets.block_public_policy != TRUE + and policy_allow_public.statement_count > 0 + ) diff --git a/policies/queries/s3/restrict_cross_account_actions.sql b/policies/queries/s3/restrict_cross_account_actions.sql new file mode 100644 index 000000000..e021ccb64 --- /dev/null +++ b/policies/queries/s3/restrict_cross_account_actions.sql @@ -0,0 +1,56 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Amazon S3 permissions granted to other AWS accounts in bucket policies should be restricted' as title, + account_id, + arn as resource_id, + 'fail' as status -- TODO FIXME +FROM ( + SELECT aws_s3_buckets.arn, + account_id, + name, + region, + -- For each Statement return an array containing the principals + CASE + WHEN + JSONB_TYPEOF(statements -> 'Principal') = 'string' THEN + JSONB_BUILD_ARRAY( statements -> 'Principal') + WHEN + JSONB_TYPEOF(statements -> 'Principal' -> 'AWS') = 'string' THEN + JSONB_BUILD_ARRAY( statements -> 'Principal' -> 'AWS' ) + WHEN + JSONB_TYPEOF(statements -> 'Principal' -> 'AWS') = 'array' THEN + statements -> 'Principal' -> 'AWS' END AS principals, + -- For each Statement return an array containing the Actions + CASE + WHEN + JSONB_TYPEOF(statements -> 'Action') = 'string' THEN + JSONB_BUILD_ARRAY(statements -> 'Action') + WHEN + JSONB_TYPEOF(statements -> 'Action') = 'array' THEN + statements -> 'Action' END AS actions + FROM aws_s3_buckets, + jsonb_array_elements( + CASE JSONB_TYPEOF(policy -> 'Statement') + WHEN 'string' THEN JSONB_BUILD_ARRAY(policy ->> 'Statement') + WHEN 'array' THEN policy -> 'Statement' + END + ) AS statements + WHERE statements -> 'Effect' = '"Allow"') AS flatten_statements, + JSONB_ARRAY_ELEMENTS(TO_JSONB(actions)) AS a, + JSONB_ARRAY_ELEMENTS(TO_JSONB(principals)) AS p +WHERE + -- Any cross account principals (or unknown principals) get flagged + ( + p.value::TEXT NOT LIKE '"arn:aws:iam::' || account_id || ':%"' + OR p.value::TEXT = '"*"' + ) + -- Any broad permissions or Deletes get flagged + AND (a.value::TEXT LIKE '"s3:%*"' + OR a.value::TEXT LIKE '"s3:DeleteObject"') + +-- This will flag ALL canoninical IDs as NOT COMPLIANT +-- This will flag ALL users that have been deleted as NOT COMPLIANT +-- This will not catch if an explicit deny supercedes the statement diff --git a/policies/queries/s3/s3_cross_region_replication.sql b/policies/queries/s3/s3_cross_region_replication.sql new file mode 100644 index 000000000..3f7724129 --- /dev/null +++ b/policies/queries/s3/s3_cross_region_replication.sql @@ -0,0 +1,16 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + '' as title, -- TODO FIXME + aws_s3_buckets.account_id, + aws_s3_buckets.arn as resource_id, + case when + aws_s3_bucket_replication_rules.status is distinct from 'Enabled' + then 'fail' else 'pass' end as status +from + aws_s3_buckets +left join aws_s3_bucket_replication_rules on aws_s3_bucket_replication_rules.bucket_cq_id=aws_s3_buckets.cq_id + +-- Note: This query doesn't validate that the destination bucket is actually in a different region diff --git a/policies/queries/s3/s3_server_side_encryption_enabled.sql b/policies/queries/s3/s3_server_side_encryption_enabled.sql new file mode 100644 index 000000000..e0d6fe6a1 --- /dev/null +++ b/policies/queries/s3/s3_server_side_encryption_enabled.sql @@ -0,0 +1,16 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'S3 buckets should have server-side encryption enabled' as title, + account_id, + arn as resource_id, + case when + aws_s3_bucket_encryption_rules.bucket_cq_id is null + then 'fail' else 'pass' end as status +from + aws_s3_buckets +left join aws_s3_bucket_encryption_rules on aws_s3_bucket_encryption_rules.bucket_cq_id=aws_s3_buckets.cq_id + +-- Note: This query doesn't validate if a bucket policy requires encryption for `put-object` requests diff --git a/policies/queries/sagemaker/sagemaker_notebook_instance_direct_internet_access_disabled.sql b/policies/queries/sagemaker/sagemaker_notebook_instance_direct_internet_access_disabled.sql new file mode 100644 index 000000000..d89a886c0 --- /dev/null +++ b/policies/queries/sagemaker/sagemaker_notebook_instance_direct_internet_access_disabled.sql @@ -0,0 +1,12 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Amazon SageMaker notebook instances should not have direct internet access' as title, + account_id, + arn as resource_id, + case when + direct_internet_access is TRUE + then 'fail' else 'pass' end as status +from aws_sagemaker_notebook_instances diff --git a/policies/queries/secretsmanager/remove_unused_secrets_manager_secrets.sql b/policies/queries/secretsmanager/remove_unused_secrets_manager_secrets.sql new file mode 100644 index 000000000..f20a32c22 --- /dev/null +++ b/policies/queries/secretsmanager/remove_unused_secrets_manager_secrets.sql @@ -0,0 +1,13 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Remove unused Secrets Manager secrets' as title, + account_id, + arn as resource_id, + case when + (last_accessed_date is null and created_date > now() - INTERVAL '90 days') + or (last_accessed_date is not null and last_accessed_date > now() - INTERVAL '90 days') + then 'fail' else 'pass' end as status +from aws_secretsmanager_secrets diff --git a/policies/queries/secretsmanager/secrets_configured_with_automatic_rotation_should_rotate_successfully.sql b/policies/queries/secretsmanager/secrets_configured_with_automatic_rotation_should_rotate_successfully.sql new file mode 100644 index 000000000..26d512ae3 --- /dev/null +++ b/policies/queries/secretsmanager/secrets_configured_with_automatic_rotation_should_rotate_successfully.sql @@ -0,0 +1,13 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Secrets Manager secrets configured with automatic rotation should rotate successfully' as title, + account_id, + arn as resource_id, + case when + (last_rotated_date is null and created_date > now() - INTERVAL '1 day' * rotation_rules_automatically_after_days) + or (last_rotated_date is not null and last_rotated_date > now() - INTERVAL '1 day' * rotation_rules_automatically_after_days) + then 'fail' else 'pass' end as status +from aws_secretsmanager_secrets diff --git a/policies/queries/secretsmanager/secrets_should_be_rotated_within_a_specified_number_of_days.sql b/policies/queries/secretsmanager/secrets_should_be_rotated_within_a_specified_number_of_days.sql new file mode 100644 index 000000000..c276d6234 --- /dev/null +++ b/policies/queries/secretsmanager/secrets_should_be_rotated_within_a_specified_number_of_days.sql @@ -0,0 +1,13 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Secrets Manager secrets should be rotated within a specified number of days' as title, + account_id, + arn as resource_id, + case when + (last_rotated_date is null and created_date > now() - INTERVAL '90 days') + or (last_rotated_date is not null and last_rotated_date > now() - INTERVAL '90 days') + then 'fail' else 'pass' end as status +from aws_secretsmanager_secrets diff --git a/policies/queries/secretsmanager/secrets_should_have_automatic_rotation_enabled.sql b/policies/queries/secretsmanager/secrets_should_have_automatic_rotation_enabled.sql new file mode 100644 index 000000000..e573ad65b --- /dev/null +++ b/policies/queries/secretsmanager/secrets_should_have_automatic_rotation_enabled.sql @@ -0,0 +1,12 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Secrets Manager secrets should have automatic rotation enabled' as title, + account_id, + arn as resource_id, + case when + rotation_enabled is distinct from TRUE + then 'fail' else 'pass' end as status +from aws_secretsmanager_secrets diff --git a/policies/queries/sns/sns_topics_should_be_encrypted_at_rest_using_aws_kms.sql b/policies/queries/sns/sns_topics_should_be_encrypted_at_rest_using_aws_kms.sql new file mode 100644 index 000000000..6048290a2 --- /dev/null +++ b/policies/queries/sns/sns_topics_should_be_encrypted_at_rest_using_aws_kms.sql @@ -0,0 +1,12 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'SNS topics should be encrypted at rest using AWS KMS' as title, + account_id, + arn as resource_id, + case when + kms_master_key_id is null or kms_master_key_id = '' + then 'fail' else 'pass' end as status +from aws_sns_topics diff --git a/policies/queries/sqs/sqs_queues_should_be_encrypted_at_rest_using_aws_kms.sql b/policies/queries/sqs/sqs_queues_should_be_encrypted_at_rest_using_aws_kms.sql new file mode 100644 index 000000000..d2641ea2b --- /dev/null +++ b/policies/queries/sqs/sqs_queues_should_be_encrypted_at_rest_using_aws_kms.sql @@ -0,0 +1,12 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'SQS queues should be encrypted at rest using AWS KMS' as title, + account_id, + arn as resource_id, + case when + kms_master_key_id is null or kms_master_key_id = '' + then 'fail' else 'pass' end as status +from aws_sqs_queues diff --git a/policies/queries/ssm/documents_should_not_be_public.sql b/policies/queries/ssm/documents_should_not_be_public.sql new file mode 100644 index 000000000..8bdf3c4ba --- /dev/null +++ b/policies/queries/ssm/documents_should_not_be_public.sql @@ -0,0 +1,13 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'SSM documents should not be public' as title, + account_id, + arn as resource_id, + case when + 'all' = ANY(account_ids) + then 'fail' else 'pass' end as status +from aws_ssm_documents +where owner in (select account_id from aws_accounts) diff --git a/policies/queries/ssm/ec2_instances_should_be_managed_by_ssm.sql b/policies/queries/ssm/ec2_instances_should_be_managed_by_ssm.sql new file mode 100644 index 000000000..7db2cd6ac --- /dev/null +++ b/policies/queries/ssm/ec2_instances_should_be_managed_by_ssm.sql @@ -0,0 +1,14 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'EC2 instances should be managed by AWS Systems Manager' as title, + aws_ec2_instances.account_id, + aws_ec2_instances.arn as resource_id, + case when + aws_ssm_instances.instance_id is null + then 'fail' else 'pass' end as status +from + aws_ec2_instances +left outer join aws_ssm_instances on aws_ec2_instances.id = aws_ssm_instances.instance_id diff --git a/policies/queries/ssm/instances_should_have_association_compliance_status_of_compliant.sql b/policies/queries/ssm/instances_should_have_association_compliance_status_of_compliant.sql new file mode 100644 index 000000000..9e1f34723 --- /dev/null +++ b/policies/queries/ssm/instances_should_have_association_compliance_status_of_compliant.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'Instances managed by Systems Manager should have an association compliance status of COMPLIANT' as title, + account_id, + aws_ssm_instances.arn, + case when + aws_ssm_instance_compliance_items.compliance_type = 'Association' + and aws_ssm_instance_compliance_items.status is distinct from 'COMPLIANT' + then 'fail' else 'pass' end as status +from + aws_ssm_instances +inner join aws_ssm_instance_compliance_items on aws_ssm_instances.cq_id = aws_ssm_instance_compliance_items.instance_cq_id diff --git a/policies/queries/ssm/instances_should_have_patch_compliance_status_of_compliant.sql b/policies/queries/ssm/instances_should_have_patch_compliance_status_of_compliant.sql new file mode 100644 index 000000000..624210016 --- /dev/null +++ b/policies/queries/ssm/instances_should_have_patch_compliance_status_of_compliant.sql @@ -0,0 +1,15 @@ +insert into aws_policy_results +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'All EC2 instances managed by Systems Manager should be compliant with patching requirements' as title, + account_id, + aws_ssm_instances.arn, + case when + aws_ssm_instance_compliance_items.compliance_type = 'Patch' + and aws_ssm_instance_compliance_items.status is distinct from 'COMPLIANT' + then 'fail' else 'pass' end as status +from + aws_ssm_instances +inner join aws_ssm_instance_compliance_items on aws_ssm_instances.cq_id = aws_ssm_instance_compliance_items.instance_cq_id diff --git a/policies/queries/waf/waf_web_acl_logging_should_be_enabled.sql b/policies/queries/waf/waf_web_acl_logging_should_be_enabled.sql new file mode 100644 index 000000000..f77df31ad --- /dev/null +++ b/policies/queries/waf/waf_web_acl_logging_should_be_enabled.sql @@ -0,0 +1,13 @@ +insert into aws_policy_results +-- WAF Classic +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'AWS WAF Classic global web ACL logging should be enabled' as title, + account_id, + arn as resource_id, + case when + logging_configuration is null or logging_configuration = '{}' + then 'fail' else 'pass' end as status +from aws_waf_web_acls diff --git a/policies/queries/wafv2/wafv2_web_acl_logging_should_be_enabled.sql b/policies/queries/wafv2/wafv2_web_acl_logging_should_be_enabled.sql new file mode 100644 index 000000000..705b2c76f --- /dev/null +++ b/policies/queries/wafv2/wafv2_web_acl_logging_should_be_enabled.sql @@ -0,0 +1,30 @@ +insert into aws_policy_results +( +-- WAF Classic +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'AWS WAF Classic global web ACL logging should be enabled' as title, + account_id, + arn as resource_id, + case when + logging_configuration is null or logging_configuration = '{}' + then 'fail' else 'pass' end as status +from aws_waf_web_acls +) +union +( +-- WAF V2 +select + :execution_time as execution_time, + :'framework' as framework, + :'check_id' as check_id, + 'AWS WAF Classic global web ACL logging should be enabled' as title, + account_id, + arn as resource_id, + case when + logging_configuration is null or logging_configuration = '{}' + then 'fail' else 'pass' end as status +from aws_wafv2_web_acls +) diff --git a/policies/views/api_gateway_method_settings.sql b/policies/views/api_gateway_method_settings.sql new file mode 100644 index 000000000..fac72b47f --- /dev/null +++ b/policies/views/api_gateway_method_settings.sql @@ -0,0 +1,23 @@ +create or replace view view_aws_apigateway_method_settings as +select + s.cq_id, + s.stage_name, + s.rest_api_cq_id, + s.arn, + s.tracing_enabled as stage_data_trace_enabled, + s.cache_cluster_enabled as stage_caching_enabled, + s.web_acl_arn as waf, + s.client_certificate_id as cert, + key as method, + ( + value::JSON -> 'DataTraceEnabled' + )::TEXT::BOOLEAN as data_trace_enabled, + (value::JSON -> 'CachingEnabled')::TEXT::BOOLEAN as caching_enabled, + ( + value::JSON -> 'CacheDataEncrypted' + )::TEXT::BOOLEAN as cache_data_encrypted, + (value::JSON -> 'LoggingLevel')::TEXT as logging_level, + r.account_id +from aws_apigateway_rest_api_stages s, aws_apigateway_rest_apis r, + JSONB_EACH_TEXT(s.method_settings) +where s.rest_api_cq_id=r.cq_id diff --git a/policies/views/log_metric_filter_and_alarm.sql b/policies/views/log_metric_filter_and_alarm.sql new file mode 100644 index 000000000..4dfc6ad29 --- /dev/null +++ b/policies/views/log_metric_filter_and_alarm.sql @@ -0,0 +1,32 @@ +create or replace view view_aws_log_metric_filter_and_alarm as +select + aws_cloudtrail_trails.account_id, + aws_cloudtrail_trails.region, + cloud_watch_logs_log_group_arn, + pattern +from aws_cloudtrail_trails +inner join aws_cloudtrail_trail_event_selectors + on + aws_cloudtrail_trails.cq_id + = aws_cloudtrail_trail_event_selectors.trail_cq_id +inner join aws_cloudwatchlogs_filters + on + aws_cloudtrail_trails.cloudwatch_logs_log_group_name + = aws_cloudwatchlogs_filters.log_group_name +inner join aws_cloudwatch_alarm_metrics + on + aws_cloudwatchlogs_filters.name + = aws_cloudwatch_alarm_metrics.metric_stat_metric_name +inner join + aws_cloudwatch_alarms on + aws_cloudwatch_alarm_metrics.alarm_cq_id + = aws_cloudwatch_alarms.cq_id +inner join + aws_sns_subscriptions on + aws_sns_subscriptions.topic_arn + = ANY(aws_cloudwatch_alarms.actions) +where is_multi_region_trail = TRUE + and is_logging = TRUE + and include_management_events = TRUE + and read_write_type = 'All' + and aws_sns_subscriptions.arn like 'aws:arn:%' diff --git a/policies/views/security_group_egress_rules.sql b/policies/views/security_group_egress_rules.sql new file mode 100644 index 000000000..a7efe7253 --- /dev/null +++ b/policies/views/security_group_egress_rules.sql @@ -0,0 +1,26 @@ +create or replace view view_aws_security_group_egress_rules as +with sg_rules_ports as ( + select + aws_ec2_security_groups.account_id, + aws_ec2_security_groups.region, + aws_ec2_security_groups.group_name, + aws_ec2_security_groups.arn, + aws_ec2_security_groups.id, + aws_ec2_security_group_ip_permissions.from_port, + aws_ec2_security_group_ip_permissions.to_port, + aws_ec2_security_group_ip_permissions.ip_protocol, + aws_ec2_security_group_ip_permissions.cq_id as permission_id + from aws_ec2_security_groups + left join + aws_ec2_security_group_ip_permissions on + aws_ec2_security_groups.cq_id = aws_ec2_security_group_ip_permissions.security_group_cq_id + where aws_ec2_security_group_ip_permissions.permission_type = 'egress' +) + +select + sg_rules_ports.*, + aws_ec2_security_group_ip_permission_ip_ranges.cidr as ip +from sg_rules_ports +left join + aws_ec2_security_group_ip_permission_ip_ranges on + sg_rules_ports.permission_id = aws_ec2_security_group_ip_permission_ip_ranges.security_group_ip_permission_cq_id diff --git a/policies/views/security_group_ingress_rules.sql b/policies/views/security_group_ingress_rules.sql new file mode 100644 index 000000000..d68ab3cd2 --- /dev/null +++ b/policies/views/security_group_ingress_rules.sql @@ -0,0 +1,26 @@ +create or replace view view_aws_security_group_ingress_rules as +with sg_rules_ports as ( + select + aws_ec2_security_groups.account_id, + aws_ec2_security_groups.region, + aws_ec2_security_groups.group_name, + aws_ec2_security_groups.arn, + aws_ec2_security_groups.id, + aws_ec2_security_group_ip_permissions.from_port, + aws_ec2_security_group_ip_permissions.to_port, + aws_ec2_security_group_ip_permissions.ip_protocol, + aws_ec2_security_group_ip_permissions.cq_id as permission_id + from aws_ec2_security_groups + left join + aws_ec2_security_group_ip_permissions on + aws_ec2_security_groups.cq_id = aws_ec2_security_group_ip_permissions.security_group_cq_id + where aws_ec2_security_group_ip_permissions.permission_type = 'ingress' +) + +select + sg_rules_ports.*, + aws_ec2_security_group_ip_permission_ip_ranges.cidr as ip +from sg_rules_ports +left join + aws_ec2_security_group_ip_permission_ip_ranges on + sg_rules_ports.permission_id = aws_ec2_security_group_ip_permission_ip_ranges.security_group_ip_permission_cq_id diff --git a/test/gen-tables.go b/test/gen-tables.go new file mode 100644 index 000000000..3c1542cda --- /dev/null +++ b/test/gen-tables.go @@ -0,0 +1,26 @@ +package main + +import ( + "context" + "fmt" + "os" + "strings" + + "github.com/cloudquery/cq-provider-aws/resources/provider" + "github.com/cloudquery/cq-provider-sdk/migration" + "github.com/cloudquery/cq-provider-sdk/provider/schema" +) + +func main() { + fmt.Println("BEGIN;") + for r, t := range provider.Provider().ResourceMap { + fmt.Printf("-- %s\n", r) + up, err := migration.CreateTableDefinitions(context.Background(), schema.PostgresDialect{}, t, nil) + if err != nil { + _, _ = fmt.Fprintf(os.Stderr, "Error creating tables for %s: %v\n", r, err) + os.Exit(1) + } + fmt.Println(strings.Join(up, "\n")) + } + fmt.Println("COMMIT;") +} diff --git a/test/policy_cq_config.hcl b/test/policy_cq_config.hcl deleted file mode 100644 index 1243d59a9..000000000 --- a/test/policy_cq_config.hcl +++ /dev/null @@ -1,23 +0,0 @@ -// Configuration AutoGenerated by CloudQuery CLI -cloudquery { - provider "aws" { - source = "cloudquery/aws" - version = "latest" - } - - // Can be configured via CLI variables - connection { - dsn = "host=localhost user=postgres password=pass database=postgres port=5432 sslmode=disable" - } -} - -// All Provider Configurations -provider "aws" { - configuration { - max_retries = 10 - max_backoff = 90 - } - resources = [ - "*", - ] -} \ No newline at end of file